某個詞組在Elasitcsearch中的某個document中存在,就必定經過某種匹配方式把它搜出來。
舉例:app
title=公路局正在治理解放大道路面積水問題。
輸入關鍵詞:道路,可否搜索到這個document呢?
實際應用中可能須要:
1)檢索關鍵詞」理解」、」解放」、」道路」、「理解放大」,都能搜出這篇文檔。
2)單個的字拆分「治」、「水」太多幹擾,不要被檢索出來。
3)待檢索的詞不在詞典中,也必需要查到。
4)待檢索詞只要在原文title或content中出現,都要檢索到。
5)檢索要快,要摒棄wildcard模糊匹配性能問題。性能
經常使用的stand標準分詞,能夠知足要求1)、3)、4)、5)。
標準分詞器是什麼鬼?
標準分析儀是默認分析儀,若是沒有指定,則默認使用該分詞器。 它提供了基於語法的標記,而且適用於大多數語言。
對於中文字符串,會逐個漢字分詞。
標準分詞器的結果以下:搜索引擎
GET /ik_index/_analyze?analyzer=standard { "text":"公路局正在治理解放大道路面積水問題" } 公,路,局,正,在,治,理,解,放,大,道,路,面,積,水,問,題
但,會出現冗餘數據很是多。 spa
針對要求2),排除match檢索,排除stand分詞。
針對要求5),排除wildcard模糊檢索。
針對要求3)、4),新詞也要被檢索到好比:「聲臨其境」、「孫大剩」等也要能被搜索到。
針對要求1),採用match_phrase貌似靠譜些。code
先使用IK-max-word細粒度分詞器,結合match_phrase試一試?blog
PUT ik_index { "mappings":{ "ik_type":{ "properties":{ "title":{ "type":"text", "fields":{ "ik_my_max":{ "type":"text", "analyzer":"ik_max_word" }, "ik_my_smart":{ "type":"text", "analyzer":"ik_smart" }, "keyword":{ "type":"keyword", "ignore_above":256 } } } } } } }
這裏,爲了驗證分詞,同時使用了ik_smart和ik_max兩種分詞。 索引
實際開發中不須要,由於:兩種分詞共存,會致使導入數據建立索引的時候,索引會很是大,對磁盤和檢索性能都會有影響。token
POST ik_index/ik_type/3 { "title":"公路局正在治理解放大道路面積水問題" }
步驟3:實施檢索開發
POST ik_index/ik_type/_search { "profile":"true", "query": { "match_phrase": { "title.ik_my_max":"道路" } } }
搜索結果以下:
無結果返回。文檔
{ "took": 1, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 0, "max_score": null, "hits": [] } }
爲何使用了max_word細粒度分詞,使用了match_pharse檢索,爲何沒有結果。
分析一下:
細粒度ik_max_word分詞結果爲:
GET /ik_index/_analyze?analyzer=ik_max_word { "text":"公路局正在治理解放大道路面積水問題" } 公路局 ,公路 ,路局 ,路 ,局正 ,正在 ,正 ,治理 ,治 ,理解 , 理 ,解放 ,解 ,放大 ,大道 ,大 ,道路 ,道 ,路面 ,路 , 面積 ,面 ,積水 ,積 ,水 ,問題
以上方式,除了能夠返回分詞結果外,還能返回詞所在的位置position。
構建索引的時候,道路被拆分爲:道路:16,道:17,路:19。(注意中間加了18:路面)
{ "token": "路面", "start_offset": 11, "end_offset": 13, "type": "CN_WORD", "position": 18 }
而檢索的時候,而道路拆分爲: 道路0 道1 路2
match_phrase檢索時候,文檔必須同時知足如下兩個條件,才能被檢索到:
1)分詞後全部詞項都出如今該字段中;
2)字段中的詞項順序要一致。
位置信息能夠被存儲在倒排索引中,所以 match_phrase 查詢這類對詞語位置敏感的查詢, 就能夠利用位置信息去匹配包含全部查詢詞項,且各詞項順序也與咱們搜索指定一致的文檔,中間不夾雜其餘詞項。
爲了驗證如上的解釋,新增一篇「道路」相關的title,檢驗一下:
POST ik_index/ik_type/4 { "title":"黨員幹部堅持走馬克思主義道路的重要性" }
注意:這時,搜索道路是能夠匹配到的。
"hits": { "total": 1, "max_score": 1.9684901, "hits": [ { "_index": "ik_index", "_type": "ik_type", "_id": "4", "_score": 1.9684901, "_source": { "title": "黨員幹部堅持走馬克思主義道路的重要性" } } ] },
細粒度ik_max_word分詞結果爲:
黨員幹部, 黨員, 幹部, 堅持走, 堅持, 堅, 持, 走馬, 馬克思主義, 馬克思,
馬克, 馬, 克, 思, 主義, 道路, 道, 路, 重要性, 重要,
要性, 性
構建索引的時候,道路被拆分爲:15,16,17位置。
與檢索的詞項順序是一致的。
這裏解析更詳細:http://t.cn/R8pzw9e
有,和match_pharse相似,不過match_phrase_prefix支持最後一個term前綴匹配。
除了把查詢文本的最後一個分詞只作前綴匹配以外,match_phrase_prefix和match_phrase查詢基本同樣,參數 max_expansions 控制最後一個單詞會被重寫成多少個前綴,也就是,控制前綴擴展成分詞的數量,默認值是50(官網文檔建議50)。
擴展的前綴數量越多,找到的文檔數量就越多;
若是前綴擴展的數量太少,可能查找不到相應的文檔,遺漏數據。
POST ik_index/ik_type/_search { "profile":"true", "query": { "match_phrase_prefix" : { "title.ik_my_max" : { "query": "道路", "max_expansions": 50 } } } }
經驗證: 關鍵詞」理解」、」解放」、」道路」、「理解放大」,都能搜出這篇文檔。
咱們本身開發搜索引擎的時候,常常會出現基於title或者content字段進行檢索。
若是用match檢索,會出現噪音不少的狀況;
若是用match_phrase,會出現某些字段檢索不出來的狀況,如上分析的「道路」;
若是用wildcard,能檢索出來,但又有性能問題的存在。
這時候,能夠考慮下: match_phrase_prefix。
實際開發中,根據應用場景不一樣,採用不一樣的分詞器。
若是選用ik,建議使用ik_max_word分詞,由於:ik_max_word的分詞結果包含ik_smart。
匹配的時候,若是想盡量的多檢索結果,考慮使用match;
若是想盡量精確的匹配分詞結果,考慮使用match_phrase;
若是短語匹配的時候,怕遺漏,考慮使用match_phrase_prefix。