1.基本概念
1.1._source
存儲的原始數據。_source中的內容就是搜索api返回的內容,如:
{
"query":{
"term":{
"title":"test"
}
}
}
結果:
{ "took": 2, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.2876821, "hits": [ { "_index": "book3", "_type": "english", "_id": "3nuFZ2UBYLvVFwGWZHcJ", "_score": 0.2876821, "_source": { "title": "test!" } } ] } }
默認情況下,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即可。
ES6.3 index屬性支持false和true,false不能搜索相當於no,true可以索引。默認使用standar分詞
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: 在6.0+ 中 , 該字段 默認被禁用,建議使用copy_to。再說_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配置(copy_to)
- _all: 在6.0+ 中 , 該字段 默認被禁用,同時在創建index的時候不能 enable;_all 字段能捕獲所有字段,它將所有其他字段的值連接成一個大字符串,使用空格作為分隔符,然后 進行分析和索引,但不存儲。這意味着它可以被搜索,但不能被檢索。 建議使用 copy_to 實現 用戶自定義的_all 功能
{ "yourtype": { "_all": { "enabled": true }, "properties": { ... } } }
也可以通過在字段中指定某個字段是否包含在_all中:
{ "yourtype": { "properties": { "field1": { "type": "string", "include_in_all": false }, "field2": { "type": "string", "include_in_all": true } } } }
如果要把字段原始值保存,要設置store屬性為true,這樣索引會更大,需要根據需求使用。下面給出測試代碼。
創建test索引:
DELETE book2
PUT book2
copy_to語法:
POST book2/english/_mapping { "english":{ "properties": { "content":{ "type":"text", "copy_to":"all_text" }, "title":{ "type":"text", "copy_to":"all_text" }, "all_text":{ "type":"text" } } } }
插入數據:
POST /book2/english/ { "title":"test!", "content":"test good Hellow" }
查詢:
POST book2/_search{
"query":{
"term":{
"all_text":"test"
}
}
}
結果:
{ "took": 13, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 0.39556286, "hits": [ { "_index": "book2", "_type": "english", "_id": "0HtjZ2UBYLvVFwGWl3f7", "_score": 0.39556286, "_source": { "title": "test!god", "content": "test good Hellow" } }, { "_index": "book2", "_type": "english", "_id": "z3tjZ2UBYLvVFwGWWXd3", "_score": 0.39556286, "_source": { "title": "test!", "content": "test good Hellow" } } ] } }
2.3.index和score配置
"index":false設置不可搜索
POST book3/english/_mapping { "english":{ "_source": { "enabled": false }, "properties": { "content":{ "type":"text", "store":true, "index":false }, "title":{ "type":"text", "store":true, "index":false } } } }
查詢:
POST book3/_search { "query":{ "term":{ "content":"test" } } } 結果: { "error": { "root_cause": [ { "type": "query_shard_exception", "reason": "failed to create query: {\n \"term\" : {\n \"content\" : {\n \"value\" : \"test\",\n \"boost\" : 1.0\n }\n }\n}", "index_uuid": "FvNPHNb7Sa6H757_lKRhpg", "index": "book3" } ], "type": "search_phase_execution_exception", "reason": "all shards failed", "phase": "query", "grouped": true, "failed_shards": [ { "shard": 0, "index": "book3", "node": "R8t6R20XQritJB_5QVQsvg", "reason": { "type": "query_shard_exception", "reason": "failed to create query: {\n \"term\" : {\n \"content\" : {\n \"value\" : \"test\",\n \"boost\" : 1.0\n }\n }\n}", "index_uuid": "FvNPHNb7Sa6H757_lKRhpg", "index": "book3", "caused_by": { "type": "illegal_argument_exception", "reason": "Cannot search on field [content] since it is not indexed." } } } ] }, "status": 400 }
正確配置:
POST book3/english/_mapping { "english":{ "_source": { "enabled": false }, "properties": { "content":{ "type":"text", "store":true, "index":"true" }, "title":{ "type":"text", "store":true, "index":"true" } } } }
高亮:
{ "query":{ "term":{ "title":"test" } }, "highlight":{ "fields":{ "title":{} } } }
結果:
{ "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.2876821, "hits": [ { "_index": "book3", "_type": "english", "_id": "2nt_Z2UBYLvVFwGWfXcn", "_score": 0.2876821, "highlight": { "title": [ "<em>test</em>!" ] } } ] } }