ES的index、store、_source和all的區別
1.基本概念
1.1._source
存儲的原始數據。_source中的內容就是搜索api返回的內容,如:
{ "query":{ "term": { "name":"國" } } }
結果:
默認情況下,Elasticsearch裏面有2份內容,一份是原始文檔,也就是_source字段裏的內容,我們在Elasticsearch中搜索文檔,查看的文檔內容就是_source中的內容。另一份是倒排索引,倒排索引中的數據結構是倒排記錄表,記錄了詞項和文檔之間的對應關系。
1.2.index:索引
index使用倒排索引存儲的是,分析器分析完的詞和文檔的對應關系。如圖:
在搜索排序的時候,查詢倒排索引要比快。
那麽文檔索引到Elasticsearch的時候,默認情況下是對所有字段創建倒排索引的(動態mapping解析出來為數字類型、布爾類型的字段除外),某個字段是否生成倒排索引是由字段的index屬性控制的,在Elasticsearch 5之前,index屬性的取值有三個:
- analyzed:字段被索引,會做分詞,可搜索。反過來,如果需要根據某個字段進搜索,index屬性就應該設置為analyzed。
- not_analyzed:字段值不分詞,會被原樣寫入索引。反過來,如果某些字段需要完全匹配,比如人名、地名,index屬性設置為not_analyzed為佳。
- no:字段不寫入索引,當然也就不能搜索。反過來,有些業務要求某些字段不能被搜索,那麽index屬性設置為no即可。
1.3.store
默認為no,被store標記的fields被存儲在和index不同的fragment中,以便於快速檢索。雖然store占用磁盤空間,但是減少了計算。store的值可以取yes/no或者true/false,默認值是no或者false。
如果在{"store":yes}的情況下,ES會對該字段單獨存儲倒排索引,每次根據ID檢索的時候,會多走一次IO來從倒排索引取數據。
而如果_source enabled 情況下,ES可以直接根據Client類來解析_source JSON,只需一次IO就將所有字段都檢索出來了。
如果需要高亮處理,這裏就要說到store屬性,store屬性用於指定是否將原始字段寫入索引,默認取值為no。如果在Lucene中,高亮功能和store屬性是否存儲息息相關,因為需要根據偏移位置到原始文檔中找到關鍵字才能加上高亮的片段。在Elasticsearch,因為_source中已經存儲了一份原始文檔,可以根據_source中的原始文檔實現高亮,在索引中再存儲原始文檔就多余了,所以Elasticsearch默認是把store屬性設置為no。
註意:如果想要對某個字段實現高亮功能,_source和store至少保留一個。
1.4._all
再說_all字段,顧名思義,_all字段裏面包含了一個文檔裏面的所有信息,是一個超級字段。以圖中的文檔為例,如果開啟_all字段,那麽title+content會組成一個超級字段,這個字段包含了其他字段的所有內容,空格隔開。當然也可以設置只存儲某幾個字段到_all屬性裏面或者排除某些字段。適合一次搜索整個文檔。
2.配置
2.1._source配置
_source字段默認是存儲的, 什麽情況下不用保留_source字段?如果某個字段內容非常多,業務裏面只需要能對該字段進行搜索,最後返回文檔id,查看文檔內容會再次到mysql或者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": { ... } } }
測試,首先創建一個索引:
PUT book2
設置mapping,禁用_source:
POST book2/english/_mapping
{ "book2": { "_source": { "enabled": false } } }
插入數據:
POST /book2/english/ { "title":"test!", "content":"test good Hellow" }
搜索"test"
POST book2/_search { "query":{ "term":{ "title":"test" } } }
結果,只返回了id,沒有_suorce,任然可以搜索到。
{ "took": 5, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.2876821, "hits": [ { "_index": "book2", "_type": "english", "_id": "zns1Z2UBYLvVFwGW4Hea", "_score": 0.2876821 } ] } }
當_source=false,store和index必須有一個為true,原始數據不保存,倒排索引必須要存儲,否則去哪裏查詢呢,驗證下:
POST book3/english/_mapping { "english":{ "_source": { "enabled": false }, "properties": { "content":{ "type":"text", "store":"false", "index":"no" }, "title":{ "type":"text", "store":"false", "index":"no" } } } }
報錯:
{ "error": { "root_cause": [ { "type": "illegal_argument_exception", "reason": "Could not convert [content.index] to boolean" } ], "type": "illegal_argument_exception", "reason": "Could not convert [content.index] to boolean", "caused_by": { "type": "illegal_argument_exception", "reason": "Failed to parse value [no] as only [true] or [false] are allowed." } }, "status": 400 }
2.2._all配置
_all字段默認是關閉的,如果要開啟_all字段,索引增大是不言而喻的。_all字段開啟適用於不指定搜索某一個字段,根據關鍵詞,搜索整個文檔內容。
開啟_all字段的方法和_source類似,mapping中的配置如下:
{ "yourtype": { "_all": { "enabled": true }, "properties": { ... } } }
也可以通過在字段中指定某個字段是否包含在_all中:
ES的index、store、_source和all的區別