Elasticsearch中有大量關鍵概念容易混淆,對於初學者來講是噩夢:前端
_source
字段裏存儲了什麼?index
屬性的做用是什麼?_all
字段?store
屬性和_source
字段有什麼關係?store
屬性和_all
字段有什麼關係?_source
字段?本文經過問答及展開描述的方式,深刻理解Elasticsearch中的_source
、_all
字段和store
、index
屬性。shell
Q:
_source
字段裏存儲了什麼?
A:原始文檔的內容。數據結構
如圖1所示, 第二象限是一份原始文檔,有title
和content
2個字段,字段取值分別爲"我是中國人"和"熱愛gongchangdang",這一點沒什麼可解釋的。咱們把原始文檔寫入Elasticsearch,默認狀況下,Elasticsearch裏面有2分內容,一份是原始文檔,也就是_source
字段裏的內容,咱們在Elasticsearch中搜索文檔,查看的文檔內容就是_source
中的內容,如圖2,相信你們必定很是熟悉這個界面。架構
另外一份是倒排索引
,倒排索引中的數據結構是倒排記錄表,記錄了詞項和文檔之間的對應關係,好比關鍵詞"中國人"包含在文檔ID爲1的文檔中,倒排記錄表中存儲的就是這種對應關係,固然也包括詞頻等更多信息。Elasticsearch底層用的是Lucene的API,Elasticsearch之因此能完成全文搜索的功能就是由於存儲有倒排索引。若是把倒排索引拿掉,Elasticsearch是否是和mongoDB很像?app
Q:
index
屬性的做用是什麼?
A:控制field是否生成倒排索引以及生成索引時是否作分詞。大數據
那麼文檔索引到Elasticsearch的時候,默認狀況下是對全部字段建立倒排索引的(動態mapping解析出來爲數字類型、布爾類型的字段除外),某個字段是否生成倒排索引是由字段的index屬性控制的,在Elasticsearch 5以前,index
屬性的取值有三個:搜索引擎
index
屬性就應該設置爲analyzed
。index
屬性設置爲not_analyzed爲佳。index
屬性設置爲no便可。Q:什麼時候應該開啓
_all
字段?
A:_all
字段開啓適用於不指定搜索某一個字段,根據關鍵詞,搜索整個文檔內容。.net
再說_all
字段,顧名思義,_all
字段是把全部其它字段中的值,以空格爲分隔符組成一個大字符串,而後被分析和索引,可是不存儲,也就是說它能被查詢,但不能被取回顯示,是一個超級字段。以圖中的文檔爲例,若是開啓_all
字段,那麼title和content的值會組成一個超級字段,固然也能夠設置只存儲某幾個字段到_all
屬性裏面或者排除某些字段。_all
字段在查詢時佔用更多的CPU和佔用更多的磁盤空間,若是確實不須要它能夠徹底的關閉它或者基於字段定製。code
_all
能讓你在不知道要查找的內容是屬於哪一個具體字段的狀況下進行搜索,例如:blog
PUT my_index/user/1 { "first_name": "John", "last_name": "Smith", "date_of_birth": "1970-10-24" } GET my_index/_search { "query": { "match": { "_all": "john smith 1970" } } }
獲得的結果是:
{ "took": 20, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.84748024, "hits": [ { "_index": "my_index", "_type": "user", "_id": "1", "_score": 0.84748024, "_source": { "first_name": "John", "last_name": "Smith", "date_of_birth": "1970-10-24" } } ] } }
Q:
store
屬性和_source
字段有什麼關係?
A:_source
是字段,store
是字段的屬性之一,Elasticsearch默認會存儲一份_source
字段做爲原始文檔。store
屬性和_source
字段配合進行設置能夠決定字段的檢索方式和是否高亮展現。
回到圖一的第一象限,用戶輸入關鍵詞"中國人",分詞之後,Elasticsearch從倒排記錄表中查找哪些文檔包含詞項"中國人 ",注意變化,分詞以前" 中國人"是用戶查詢(query),分詞以後在倒排索引中" 中國人"是詞項(term)。Elasticsearch根據文檔ID(一般是文檔ID的集合)返回文檔內容給用戶,如圖一第四象限所示。
一般狀況下,對於用戶查詢的關鍵字要作高亮處理,如圖3所示:
關鍵字高亮實質上是根據倒排記錄中的詞項偏移位置,找到關鍵詞,加上前端的高亮代碼。這裏就要說到store
屬性,store
屬性用於指定是否將原始字段寫入索引,默認取值爲false。若是在Lucene中,高亮功能和store
屬性是否存儲息息相關,由於須要根據偏移位置到原始文檔中找到關鍵字才能加上高亮的片斷。二者不一樣取值時對字段檢索和高亮的影響以下表:
enabled | store 爲true的字段從倒排索引裏檢索,浪費IO次數; |
全部字段根據Client類解析存儲的 _source JSON串進行檢索,僅需一次IO; |
disabled | store 爲true的字段從倒排索引裏檢索,其餘字段能檢索不能高亮展現; |
全部字段只能檢索,不能高亮展現; |
_source\store
|
true
|
false
|
---|
在Elasticsearch,由於_source
中已經存儲了一份原始文檔,能夠根據_source
中的原始文檔實現高亮,在索引中再存儲原始文檔就多餘了,因此Elasticsearch默認是把store
屬性設置爲false。
若是想要對某個字段實現高亮功能,_source
和store
至少保留一個。下面給出一個例子,設置test索引不保存_source,title字段索引但不分析,字段原始值寫入索引,content字段爲默認屬性,代碼以下:
PUT test/test/_mapping { "test": { "_source": { "enabled": false }, "properties": { "title": { "type": "string", "index": "not_analyzed", "store": "true" }, "content": { "type": "string" } } } }
GET test/_search { "query": { "match": { "title": "我是中國人" } }, "highlight": { "fields": { "title": {} } } }
{ "took": 6, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.30685282, "hits": [ { "_index": "test", "_type": "test", "_id": "1", "_score": 0.30685282, "highlight": { "title": [ "<em>我是中國人</em>" ] } } ] } }
從返回結果中能夠看到,雖然沒有保存title字段到_source, 可是依然能夠實現搜索高亮。
{"store": true}
既然這麼費力不討好,可是仍然有兩個應用場景:
Q:
store
屬性和_all
字段有什麼關係?
A:_all
字段擁有store
屬性,是從屬關係。store
屬性決定了_all
字段是否能夠被高亮展現。
首先store
是_all
字段的一個屬性,_all
字段默認不屬於_source
,而且store
屬性默認爲false,因此不能被高亮展現。若是但願被高亮展現,則有兩種方式:
_all
字段的store
爲true,代價是大量的冗餘存儲;Q:什麼狀況下不用保留
_source
字段?
A:須要存儲海量文檔,Elasticsearch在架構中只作索引,存儲選型爲相似HBase的NoSQL,不存儲_source
能夠極大減小存儲開銷(Elasticsearch每每用的是SSD)。
_source
字段默認是存儲的, 什麼狀況下不用保留_source字段?若是某個字段內容很是多,業務只須要能對該字段進行搜索,最後返回文檔id,查看文檔內容會再次到HBase中取數據,把大字段的內容存在Elasticsearch中只會增大索引,這一點文檔數量越大結果越明顯,若是一條文檔節省幾KB,放大到億萬級的量結果也是很是可觀的。 若是想要關閉_source
字段,在mapping
中的設置以下:
{ "yourtype":{ "_source":{ "enabled":false }, "properties": { ... } } }
若是隻想存儲某幾個字段的原始值到Elasticsearch,能夠經過incudes
參數來設置,在mapping
中的設置以下:
{ "yourtype":{ "_source":{ "includes":["field1","field2"] }, "properties": { ... } } }
一樣,能夠經過excludes
參數排除某些字段:
{ "yourtype":{ "_source":{ "excludes":["field1","field2"] }, "properties": { ... } } }
至此,文章開頭提出的幾個問題都給出了答案。特別參考了這篇文章:圖解Elasticsearch中的_source、_all、store和index屬性。
做者:大數據之心連接:http://www.jianshu.com/p/0908b9ee65fc來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。