Elasticsearch中有幾個關鍵屬性容易混淆,不少人搞不清楚_source字段裏存儲的是什麼?store屬性的true或false和_source字段有什麼關係?store屬性設置爲true和_all有什麼關係?index屬性又起到什麼做用?何時設置store屬性爲true?何時應該開啓_all字段?本文經過圖解的方式,深刻理解Elasticsearch中的_source、_all、store和index屬性。前端
如圖1所示, 第二象限是一份原始文檔,有title和content2個字段,字段取值分別爲」我是中國人」和」 熱愛」,這一點沒什麼可解釋的。咱們把原始文檔寫入Elasticsearch,默認狀況下,Elasticsearch裏面有2分內容,一份是原始文檔,也就是_source字段裏的內容,咱們在Elasticsearch中搜索文檔,查看的文檔內容就是_source中的內容,如圖2,相信你們必定很是熟悉這個界面。 mysql
另外一份是倒排索引,倒排索引中的數據結構是倒排記錄表,記錄了詞項和文檔之間的對應關係,好比關鍵詞」中國人」包含在文檔ID爲1的文檔中,倒排記錄表中存儲的就是這種對應關係,固然也包括詞頻等更多信息。Elasticsearch底層用的是Lucene的API,Elasticsearch之因此能完成全文搜索的功能就是由於存儲的有倒排索引。若是把倒排索引拿掉,Elasticsearch是否是和mongoDB很像?
那麼文檔索引到Elasticsearch的時候,默認狀況下是對全部字段建立倒排索引的(動態mapping解析出來爲數字類型、布爾類型的字段除外),某個字段是否生成倒排索引是由字段的index屬性控制的,在Elasticsearch 5以前,index屬性的取值有三個:sql
analyzed:字段被索引,會作分詞,可搜索。反過來,若是須要根據某個字段進搜索,index屬性就應該設置爲analyzed。
not_analyzed:字段值不分詞,會被原樣寫入索引。反過來,若是某些字段須要徹底匹配,好比人名、地名,index屬性設置爲not_analyzed爲佳。
no:字段不寫入索引,固然也就不能搜索。反過來,有些業務要求某些字段不能被搜索,那麼index屬性設置爲no便可。數據結構
再說_all字段,顧名思義,_all字段裏面包含了一個文檔裏面的全部信息,是一個超級字段。以圖中的文檔爲例,若是開啓_all字段,那麼title+content會組成一個超級字段,這個字段包含了其餘字段的全部內容,固然也能夠設置只存儲某幾個字段到_all屬性裏面或者排除某些字段。回到圖一的第一象限,用戶輸入關鍵詞" 中國人",分詞之後,Elasticsearch從倒排記錄表中查找哪些文檔包含詞項"中國人 ",注意變化,分詞以前" 中國人"是用戶查詢(query),分詞以後在倒排索引中" 中國人"是詞項(term)。Elasticsearch根據文檔ID(一般是文檔ID的集合)返回文檔內容給用戶,如圖一第四象限所示。一般狀況下,對於用戶查詢的關鍵字要作高亮處理,如圖3所示:app
關鍵字高亮實質上是根據倒排記錄中的詞項偏移位置,找到關鍵詞,加上前端的高亮代碼。這裏就要說到store屬性,store屬性用於指定是否將原始字段寫入索引,默認取值爲no。若是在Lucene中,高亮功能和store屬性是否存儲息息相關,由於須要根據偏移位置到原始文檔中找到關鍵字才能加上高亮的片斷。在Elasticsearch,由於_source中已經存儲了一份原始文檔,能夠根據_source中的原始文檔實現高亮,在索引中再存儲原始文檔就多餘了,因此Elasticsearch默認是把store屬性設置爲no。注意:若是想要對某個字段實現高亮功能,_source和store至少保留一個。下面會給出測試代碼。至此,文章開頭提出的幾個問題都給出了答案。下面給出這幾個字段經常使用配置的代碼。測試
_source字段默認是存儲的, 什麼狀況下不用保留_source字段?若是某個字段內容很是多,業務裏面只須要能對該字段進行搜索,最後返回文檔id,查看文檔內容會再次到mysql或者hbase中取數據,把大字段的內容存在Elasticsearch中只會增大索引,這一點文檔數量越大結果越明顯,若是一條文檔節省幾KB,放大到億萬級的量結果也是很是可觀的。 若是想要關閉_source字段,在mapping中的設置以下:spa
{ "yourtype":{ "_source":{ "enabled":false }, "properties": { ... } } }
若是隻想存儲某幾個字段的原始值到Elasticsearch,能夠經過incudes參數來設置,在mapping中的設置以下: .net
{ "yourtype":{ "_source":{ "includes":["field1","field2"] }, "properties": { ... } } }
一樣,能夠經過excludes參數排除某些字段:code
{ "yourtype":{ "_source":{ "excludes":["field1","field2"] }, "properties": { ... } } }
測試,首先建立一個索引,設置mapping,禁用_source:blog
PUT test/test/_mapping
{
"test": {
"_source": {
"enabled": false
}
}
}
POST test/test/1 { "title":"我是中國人", "content":"熱愛" }
搜索關鍵詞」中國人」:
GET test/_search { "query": { "match": { "title": "中國人" } } } { "took": 9, "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 } ] } }
從返回結果中能夠看到,搜到了一條文檔,可是禁用_source之後查詢結果中不會再返回文檔原始內容。(注,測試基於ELasticsearch 2.3.3,配置文件中已默認指定ik分詞。
_all字段默認是關閉的,若是要開啓_all字段,索引增大是不言而喻的。_all字段開啓適用於不指定搜索某一個字段,根據關鍵詞,搜索整個文檔內容。
開啓_all字段的方法和_source相似,mapping中的配置以下:
"yourtype": { "_all": { "enabled": true }, "properties": { ... } } }
也能夠經過在字段中指定某個字段是否包含在_all中:
{ "yourtype": { "properties": { "field1": { "type": "string", "include_in_all": false }, "field2": { "type": "string", "include_in_all": true } } } }
若是要把字段原始值保存,要設置store屬性爲true,這樣索引會更大,須要根據需求使用。設置mapping,這裏設置全部字段都保存在_all中而且存儲原始值:
PUT test/test/_mapping
{
"test": {
"_all": {
"enabled": true,
"store": true
}
}
}
POST test/test/1 { "title":"我是中國人", "content":"熱愛" }
對_all字段進行搜索並高亮:
POST test/_search { "fields": ["_all"], "query": { "match": { "_all": "中國人" } }, "highlight": { "fields": { "_all": {} } } } { "took": 3, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.15342641, "hits": [ { "_index": "test", "_type": "test", "_id": "1", "_score": 0.15342641, "_all": "我是中國人 熱愛 ", "highlight": { "_all": [ "我是<em>中國人</em> 熱愛 " ] } } ] } }
Elasticsearch中的query_string和simple_query_string默認就是查詢_all字段,示例以下:
GET test/_search { "query": { "query_string": { "query": "公公公" } } }
index和store屬性是在字段內進行設置的,下面給出一個例子,設置test索引不保存_source,title字段索引但不分析,字段原始值寫入索引,content字段爲默認屬性,代碼以下:
DELETE test PUT test PUT test/test/_mapping { "test": { "_source": { "enabled": false }, "properties": { "title": { "type": "string", "index": "not_analyzed", "store": "true" }, "content": { "type": "string" } } } }