干貨 | Elasticsearch 檢索類型選型指南
之前在 DSL 中一次問卷調(diào)查中,收集到如下幾個和搜索類型相關(guān)的問題。
Q1:麻煩講一下es常用的查詢關(guān)鍵詞,及使用場景,比如term、match、should、filter等等,謝謝老大...... Q2:講下查詢term,match,match_pharse,operator,mget,multi_match等的用法和區(qū)別? Q3:term、match、phrase、bool query等常用語法,及對不同類型數(shù)據(jù)字段的支持。在分詞場景下的區(qū)別? Q4:fuzzy查詢的fuzziness參數(shù)不同取值,minimumshouldmatch不同取值負(fù)數(shù),百分比等…... Q5:希望可以通俗一點??梢杂幸曨l和文檔~~
這些問題經(jīng)常會被問到,今天我們從如下幾個方面詳細(xì)解讀一下。
宏觀俯瞰 Elasticsearch 檢索分類; 分類解讀各個搜索類型特點及應(yīng)用場景; 各個檢索類型的區(qū)別。
1、宏觀俯瞰 Elasticsearch 檢索分類

這么看,貌似不夠清晰,來張腦圖梳理一下。

常用的部分下文會詳細(xì)解讀,不常用的建議大家使用前優(yōu)先閱讀一遍官方文檔,做到“知己知彼、有的放矢”。
貌似清晰了很多。
說一下,我在初學(xué) Elasticsearch 犯過的“錯誤”或者遇到的問題,看看大家有沒有“中招”。
第一:一把梭用法
Match 檢索很好用,召回數(shù)據(jù)又多。業(yè)務(wù)凡是涉及檢索都是 Match query。
用星爺?shù)脑挿浅?yīng)景:“曾經(jīng)有一堆檢索類型放在我面前,我沒有珍惜。我挑出 use 最多最爽的 Match query 用的樂此不疲。當(dāng)召回了一大批不相關(guān)的數(shù)據(jù)才后悔莫及!如果老天再給我一次選型的機會的話,我會優(yōu)先考慮 Match_phrase"。

圖片來自網(wǎng)絡(luò)
這么說,大家可能沒有感覺,后文會有詳細(xì)示例說明。
第二:自己代碼實現(xiàn)“與或非”檢索。
由于對于檢索類型了解不全,只知道有限的幾種類型:term、match、terms等。
不知道 query string 檢索類型已經(jīng)實現(xiàn)了:“AND OR NOT” 與或非檢索。
自己實現(xiàn)花了時間不說,也不如 query string 自身實現(xiàn)考慮的全面。
第三:數(shù)百個 wildcard 模糊匹配組合導(dǎo)致演示現(xiàn)場集群宕機
這個我在這篇文章有過詳細(xì)說明,不再贅述。
如上,回頭看,出現(xiàn)問題體現(xiàn)在:
檢索類型了解不全,拿來就用;
不能分辨不同檢索類型的應(yīng)用場景和可能的副作用;
項目著急只關(guān)注了能用,沒有關(guān)注“用好”、“好用”。
2、精準(zhǔn)匹配檢索和全文檢索的本質(zhì)區(qū)別
本文繼續(xù)縮小范圍,把重心縮小為最常用的:精準(zhǔn)匹配檢索、全文檢索、組合檢索三種類型。
精準(zhǔn)匹配檢索和全文檢索的本質(zhì)區(qū)別:
精準(zhǔn)匹配把檢索的整個文本不做分詞處理,當(dāng)前一個串整體處理。
而全文檢索需要分詞處理,對分詞后的每個詞單獨檢索然后大bool組合檢索。
文章后續(xù)內(nèi)容以如下數(shù)據(jù)示例展開討論:
PUT?test-0415
{
??"mappings":?{
????"properties":?{
??????"title":?{
????????"type":?"text",
????????"analyzer":?"ik_max_word",
????????"fields":?{
??????????"keyword":?{
????????????"type":?"keyword"
??????????}
????????}
??????}
????}
??}
}
POST?test-0415/_bulk
{"index":{"_id":1}}
{"title":"烏蘭圖雅經(jīng)典歌曲30首連播?標(biāo)清_手機樂視視頻"}
{"index":{"_id":2}}
{"title":"烏蘭縣地區(qū)生產(chǎn)總值22.9億元?"}
{"index":{"_id":3}}
{"title":"烏蘭新聞網(wǎng)歡迎您!"}
{"index":{"_id":4}}
{"title":"烏蘭:你說急什么呢,我30歲了"}
{"index":{"_id":5}}
{"title":"千城勝景丨勝境美譽?多彩烏蘭"}
精準(zhǔn)匹配和全文檢索的區(qū)別,如下一例說得清楚:
POST?test-0415/_search
{
??"query":?{
????"match":?{
??????"title":?"烏蘭新聞網(wǎng)歡迎您!"
????}
??}
}
召回數(shù)據(jù)(只截取了title)如下:

也就是說:檢索“烏蘭新聞網(wǎng)歡迎您!”召回了全部數(shù)據(jù)!
為啥?
檢索語句加上“profile:true”,一探究竟:

一句話:match_query 在檢索的時候?qū)⒋龣z索字符串做了分詞處理。
如上所示:檢索的時候“烏蘭新聞網(wǎng)歡迎您”切詞后變成 [ “烏蘭”, "新聞網(wǎng)", "新聞”,“網(wǎng)”,“歡迎您”, “歡迎”, “您”]。
有同學(xué)會問,咋分的呢?通過 analyzer API 可以看出。

然后,我們再看一下精準(zhǔn)匹配的檢索實現(xiàn)。
POST?test-0415/_search
{
??"profile":?true,?
??"query":?{
????"term":?{
??????"title.keyword":?"烏蘭新聞網(wǎng)歡迎您!"
????}
??}
}
profile:true 看到結(jié)果如下:

也就是說,精準(zhǔn)匹配是拿整個文本串一起 term query檢索的,不做分詞處理。
有了這個大前提,后面才好理解一些。
接下來,分類解讀各個搜索特點及應(yīng)用場景。
3 精準(zhǔn)匹配檢索
3.1 Term 單字段精準(zhǔn)匹配、
Term query 應(yīng)用場景:單值精準(zhǔn)匹配。
注意點:避免將 term query 應(yīng)用到 text 類型的檢索。
再延伸一些,Term 檢索針對的是非 text 類型,term 針對 text 類型并不會報錯,但結(jié)果會達不到預(yù)期。
有同學(xué)說:我非要將 text 類型應(yīng)用 term query會怎么樣?來吧,看一下效果:
DELETE?my-index-000001
#?不指定分詞器就使用默認(rèn):standard 分詞器。
PUT?my-index-000001
{
??"mappings":?{
????"properties":?{
??????"full_text":?{
????????"type":?"text"
??????}
????}
??}
}
#?寫入數(shù)據(jù)
PUT?my-index-000001/_doc/1
{
??"full_text":?"Quick?Brown?Foxes!"
}
#?執(zhí)行檢索,并不會召回數(shù)據(jù)
GET?my-index-000001/_search?pretty
{
??"profile":?true,?
??"query":?{
????"term":?{
??????"full_text":?"Quick?Brown?Foxes!"
????}
??}
}

檢索結(jié)果如上圖所示,為啥沒有召回結(jié)果數(shù)據(jù)?
原因在于:寫入的時候,Quick Brown Foxes! 經(jīng)過默認(rèn)分詞器 standard 處理后,轉(zhuǎn)化為:quick、brown、foxes 存儲。

而檢索的時候,咱們檢索的是:“Quick Brown Foxes”,如下所示。所以:沒有數(shù)據(jù)召回。

3.2 Terms 多字段精準(zhǔn)匹配
Terms query 應(yīng)用場景:多值精準(zhǔn)匹配。
注意點:同 term query核心區(qū)別:terms query 支持多個值,而 term query 僅支持單個值。
3.3 Range 范圍檢索
Range query 應(yīng)用場景:區(qū)間范圍檢索。
注意點1:當(dāng)“search.allow_expensive_queries”設(shè)置為 false 時,range query 在 text 和 keyword 類型的檢索不能被執(zhí)行。
注意點2:range query 對 text、keyword 類型的區(qū)間檢索實際意義不大。

3.4 Exists 是否存在檢索
Exists query 應(yīng)用場景:判定字段是否有值。
特例很多,建議參考官方文檔,這里僅強調(diào)一個:
DELETE?test-0001
PUT?test-0001
{
??"mappings":?{
????"properties":?{
??????"title":?{
????????"type":?"text",
????????"index":?false
??????}
????}
??}
}
POST?test-0001/_bulk
{"index":{"_id":1}}
{"title":"1"}
POST?test-0001/_search
{
??"profile":?true,?
??"query":?{
????"exists":?{
??????"field":?"title"
????}
??}
}
如上的 exists query 本質(zhì)上走的是:“ConstantScore(NormsFieldExistsQuery [field=title])“ 檢索,由于 title 字段沒有被索引,所以沒有結(jié)果召回。
3.5 Wildcard 類Mysql like 檢索
Wildcard 應(yīng)用場景:通配符檢索,類似 MySQL like 查詢。
注意:非必要,不使用??聪旅娼貓D就知道原因。

推薦閱讀:Elasticsearch 警惕使用 wildcard 檢索!然后呢?
3.6 prefix 前綴匹配檢索
prefix Query應(yīng)用場景:前綴匹配。
先看一個社區(qū)實戰(zhàn)問題:https://elasticsearch.cn/question/12595
比如我有3個文檔,采用ik_max_word分詞。
1.?考試專題
2.?測試考試成績
3.?新動能考試
如何做到真正的前綴搜索?
prefix 可以搞定,針對 keyword 類型才可以。
DELETE?test0416
PUT?test0416
{
??"mappings":?{
????"properties":?{
??????"title":?{
????????"type":?"text",
????????"analyzer":?"ik_max_word",?
????????"fields":?{
??????????"keyword":?{
????????????"type":?"keyword"
??????????}
????????}
??????}
????}
??}
}
POST?test0416/_bulk
{"index":{"_id":1}}
{"title":"考試專題"}
{"index":{"_id":2}}
{"title":"測試考試成績題"}
{"index":{"_id":3}}
{"title":"新動能考試"}
POST?test0416/_search
{
??"query":?{
????"prefix":?{
??????"title.keyword":?{
????????"value":?"考試"
??????}
????}
??}
}
3.7 Terms set 檢索
Terms set Query 應(yīng)用場景:term query 檢索 1個滿足條件,terms query檢索多個滿足條件,而 Terms set query 介于兩者中間。
3.8 Fuzzy 支持編輯距離的模糊查詢
Fuzzy Query 應(yīng)用場景:返回包含與搜索詞相似的詞的文檔,也就是說:有一定的類似糾錯功能。
3.9 IDs 檢索
IDS query:基于 ID 組召回數(shù)據(jù)。
3.10 Regexp 正則匹配檢索
Regexp Query:基于正則表達式的檢索。
使用建議:非必要不使用。
4、全文檢索類型
4.1 Match 檢索
Match Query 應(yīng)用場景:召回率要求高、精準(zhǔn)度要求不高的場景。
使用建議:精準(zhǔn)度要求高的場景慎用。
如前所述,Match 的本質(zhì):大 bool + term query 組合體。

4.2 Match phrase 短語檢索
Match phrase Query 應(yīng)用場景:更注重精準(zhǔn)度召回的場景,match query 如果叫做分詞檢索的話,match phrase 叫短語匹配檢索更為合適。
注意1:檢索的時候可以指定分詞器。
注意2:分詞器指定不同,拼接的串中字符的切分粒度不同。
如下兩個截圖分別使用了:standard 標(biāo)準(zhǔn)分詞器以及 ik_smart 粗粒度 IK 分詞器。


4.3 Multi-match 檢索
Multi-match query 應(yīng)用場景:多字段的 match query。
注意:多字段就涉及評分的整合,所以會有:most_fields、best_fields、cross_fields 等評分方式。
4.4 Match_phrase_prefix 檢索
Match_phrase_prefix query 應(yīng)用場景:短語匹配+前綴匹配的組合體,適用于短語前綴匹配。
如下所示:

個人認(rèn)為,新聞、新聞網(wǎng)是根據(jù)已有文本的 IK 分詞(寫入時指定的分詞器 ik_max_word)的結(jié)果。
4.5 query_string 檢索
query_string query 應(yīng)用場景:與或非表達式的檢索。
AND:代表與,OR 代表或,NOT 代表非。
非常復(fù)雜的語法,建議參考官方文檔。
4.6 simple_query_string 檢索
simple_query_string 應(yīng)用場景:同 query_string 。
核心不同點:simple_query_string 在語法不對時,并不會報錯。


還有幾種:Intervals query、Match boolean prefix query、Combined fields query,應(yīng)用場景相對受限,我沒有展開,大家根據(jù)官方文檔選型即可。
5 組合檢索類型
如果把上文的“精準(zhǔn)匹配檢索”和“全文檢索”比作單兵種作戰(zhàn),那么組合檢索就可以看做“海陸空”全方位作戰(zhàn)。
組合檢索主要分為兩大類:bool 組合檢索和自定義評分檢索。
5.1 bool 組合檢索
適用場景:復(fù)雜條件的組合檢索。當(dāng)單個或者單類檢索條件不能適配復(fù)雜組合檢索的時候,優(yōu)先考慮 bool 組合條件檢索。
其下可以包含但不限于:
must:必須滿足條件。 must_not:必須不滿足條件(忽略評分,召回數(shù)據(jù)評分為0)。 filter:過濾條件(忽略評分,召回數(shù)據(jù)評分為0),可以借助緩存提升性能。 should:部分條件滿足,由minmum_should_match控制。


5.2 自定義評分檢索
適用場景:傳統(tǒng)基于BM25(詞頻TF、逆文檔頻率IDF)機制不能滿足評分要求,某一個或者多個字段需要提升、降低或者修改權(quán)重比例的時候,優(yōu)先考慮自定義評分實現(xiàn)。
如果自定義評分也無法滿足,那只能自己開發(fā)評分插件實現(xiàn)。
自定義評分推薦閱讀:實戰(zhàn) | Elasticsearch自定義評分的N種方法
6、總結(jié)
說到這里,開篇問題基本都能回答上了。檢索類型選型流程參考如下:

全文檢索(Full text query)類檢索
- Match 適用于:召回率高、精準(zhǔn)度不高的場景;
- Match phrase 適用于:精準(zhǔn)度高、召回率不高的場景;
- Match phrase prefix 適用于:短語前綴匹配檢索;
- Mulit-match 適用于:多字段檢索;
- Query string 適用于:支持與或非表達式的檢索;
- Simple query string:較 query string 容錯率高的場景;
精準(zhǔn)匹配(Term-level query)類檢索
- Term 適用于:單字段精準(zhǔn)匹配;
- Terms 適用于:多字段精準(zhǔn)匹配;
- Range 適用于:范圍檢索;
- Exists 適用于:判定是否存在檢索;
- Wildcard 適用于:類Mysql like 檢索,非必要不使用;
- prefix 適用于:前綴匹配檢索;
- Fuzzy 適用于:支持編輯距離的模糊查詢;
- IDs 適用于:基于文檔id組檢索的場景;
- Regexp 適用于:正則匹配檢索,非必要不使用。

大家有好的選型意見和建議,歡迎留言討論。
參考
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
推薦
更短時間更快習(xí)得更多干貨!
和全球?1600+?Elastic 愛好者一起精進!

