?序
????????2024年4月,小組計算建設標簽平臺,使用ES等工具建了一個demo,由于領導變動關系,項目基本夭折。其實這兩年也陸陸續續接觸和使用過ES,兩年前也看過ES的官網,當時剛畢業半年多,由于歷史局限性導致根本看不懂。因此趁著這個機會,在5月~6月期間,基本看了一遍ES的官方文檔,先從整體梳理了ES的基礎知識,共四期。
Elasticsearch 第一期:ES的前世今生-CSDN博客
Elasticsearch 第二期:基礎的基礎概念-CSDN博客
Elasticsearch 第三期:倒排索引,分析,映射-CSDN博客
Elasticsearch 第四期:搜索和過濾-CSDN博客
前言
這篇文章的內容是根據ES官方關于搜索的章節整理的。但目錄結構做了重新整理。分別從相關性,搜索,過濾進行了介紹。具體如下:
相關性
ES搜索的本質其實是把文檔根據搜索內容進行相關性排序。所以在介紹ES搜索之前,先簡單介紹一下ES相關性。關于相關性的理論知識具體可以參考官網。當然相關性得分只是搜索排序的一種,還有特殊場景的排序方法,如地理位置鄰近算法。
眾所周知,查詢語句會為每個文檔生成一個評分:?_score
?。通常我們說的?相關性?是用來計算全文本字段的值相對于全文本檢索詞相似程度的算法。
Elasticsearch?的相似度算法被定義為:TF/IDF(檢索詞頻率/反向文檔頻率)?。
檢索詞頻率:檢索詞在該字段出現的頻率。出現頻率越高,相關性也越高。?字段中出現過?5?次要比只出現過?1?次的相關性高。
反向文檔頻率:每個檢索詞在全部索引中出現的頻率。頻率越高,計算相關時相關性的權重越低。檢索詞出現在多數文檔中會比出現在少數文檔中的權重更低。
字段長度準則:該字段的長度是多少。長度越長,相關性越低。?檢索詞出現在一個短的?title?要比同樣的詞出現在一個長的?content?字段權重更大。
檢索詞頻率 | title:dog?love?person | 很明顯,dog在第二個文檔中出現了2次,因此文檔2相關性更強 |
title:dog?love?dog | ||
反向文檔頻率 | title:dog?love?person | 當使用dog和person來搜索時,雖然文檔2被命中了2次,但person在全部文檔中出現了頻率比dog少,因此計算person相關性權重的時候會更大 |
title:dog?love?dog | ||
字段長度準則 | title:dog?love?person | 搜索love時可以名字兩個文檔,但文檔2中的字段相對較短,其得分更高。 |
title:dog?love?dog |
搜索
搜索的過程就是在全文字段中搜索到最相關的文檔。搜索兩個最重要的方面是:
相關性(Relevance)它是評價查詢與其結果間的相關程度,并根據這種相關程度對結果排名的一種能力
分析(Analysis)它是將搜索關鍵字和文檔內容轉換為有區別的、規范化的?詞項(token)?的一個過程。?目的是為了(a)創建倒排索引 (b)查詢倒排索引。
在Elasticsearch?7.x中,它提供了三種主要的文檔檢索方式:全文搜索、詞項搜索和復合搜索。
全文搜索
簡單查詢
全文搜索是Elasticsearch最常見的搜索方式,主要用于搜索文本字段。用戶只需要提供關鍵詞,Elasticsearch就能自動地在索引中找到包含這些關鍵詞的文檔。在全文搜索中,Elasticsearch使用了一種名為“倒排索引”的數據結構,可以非常高效地執行搜索操作。
全文搜索主要通過match
查詢實現。match
查詢會對用戶給出的關鍵詞進行解析,然后進行分詞處理。只要查詢語句中的任意一個詞項在文檔中被匹配,該文檔就會被檢索到。
全文搜索經常用的命令包括:
match | 匹配查詢,用于單字段搜索 |
multi_match | 在多個字段上反復執行相同查詢 |
match
{"query": {"match": {"title":{"query":"BROWN DOG!","operator":and //所有詞項都要匹配時"minimum_should_match":"50%"}}}
}
上面是match搜索的一個用例。搜索內容可以是一個詞項,也可以是多個詞項。若是多個詞項場景,這些詞語會被解析成單個詞,然后在倒序索引中進行精確(term)查找。默認是這些詞之間的關系是or,即滿足文檔中包含其中一個詞就會被找到。
match有兩個參數來控制搜索操作和返回結果。
-
operator
:需要搜索的關鍵詞必須全部出現 -
minimum_should_match
?:最小匹配參數
有時候需要搜索的關鍵詞必須全部出現,可以使用參數?operator
?,設置為?and
?。
若文檔數量超多,可以對相關性設定閾值,而我們只希望返回相關性高的文檔,?可以使用?minimum_should_match
?最小匹配參數。該參數的值設置有兩種方式,指定必須匹配的詞項數用來表示一個文檔是否相關。具體數值可以參考:
1.?設置為某個具體數字來制定匹配的詞項數量
2.?將其設置為一個百分數:百分數可以設置為正值(75%)也可以設置為負值(-25%)。計算必須文檔中要匹配的詞項數量
75% | -25% | |
4個搜索關鍵詞 | 4*75%=3 | 4-4*25%=3 |
4個搜索關鍵詞 | 5*75%=3(向下取整) | 5-5*25%=4(向下取整) |
multi_match
multi_match
?則是match在多字段查到的一個簡便方式。可以在能在多個字段上反復執行相同查詢。
{"query":{"multi_match": {"query": "BROWN DOG","fields":["title","body"]}}
短語近似匹配
簡單查詢中match
?或者multi_match
查詢可以獲得包含查詢詞條的文檔。但搜索查詢時沒有考慮詞語之間的關系(如:位置關系,詞性關系),甚至都不能確定匹配到的內容是否來自同一個字段。
1. Java是一門很好的語言,很多工程師都喜歡使用.
2. Java工程師都很優秀.
用?match
?搜索?Java?工程師
?上面的兩個文檔都會得到匹配,但很明顯,其實文檔2是我們需要的可能性更大。
當使用分析器將文檔內容和搜索關鍵詞進行分詞之后,理解分詞之間的關系是一個復雜的難題。我們也無法通過更換查詢方式或者底層存儲結構來解決分詞問題。但我們至少可以通過出現在彼此附近或者相鄰的分詞來判斷分詞之間的相關性。
這就是短語匹配或者近似匹配的所屬領域。對于短語匹配,match_phrase
也是經常用的搜索方式之一。例如下面的例子:
{"query": {"match_phrase": {"title": {"query":"quick brown fox","slop":2}}}
}
對于與match
和multi_match
查詢不同的是,除了將查詢關鍵字解析成一個詞項,然后在倒排索引中進行搜索查詢外,match_phrase
還會比較快搜索詞項之間的位置,最終結果只會保留?位置?與搜索詞項相同的文檔。?
精確短語匹配?或許是過于嚴格了。也許我們想要包含?“Java?高級?工程師”?的文檔也能夠匹配?“Java?工程師,”?,可以通過使用?slop
?參數將靈活度引入短語匹配中。
slop
?參數告訴?match_phrase
?查詢詞條相隔多遠時仍然能將文檔視為匹配?。?相隔多遠的意思是為了讓查詢和文檔匹配你需要移動詞條多少次。
詞項搜索
詞項搜索與全文搜索不同,查詢不會對輸入進行分詞處理,而是將輸入作為一個整體進行搜索。詞項搜索方式本文整理了精確查找--term和部分匹配搜索。
精確查找和范圍查找
我們首先來看最為常用的?term
?查詢和range查詢。正如上面所說,詞項搜索不會對輸入進行分詞處理,而是將輸入作為一個整體,在倒排索引中查找準確的詞項。term和range一般適用于用來處理數字(numbers)、布爾值(Booleans)、日期(dates)等。
term | 查詢某個字段等于搜索詞的文檔 | "term":{?"address":"香港"} 查詢地址等于'香港'的文檔? |
terms | 查詢某個字段里包含多個關鍵詞的文檔 | terms":{???"address":["香港","北京"]} 查詢地址等于"香港"或"北京"的 |
range | 實現范圍查詢 | "range":?{ ????????????"age":?{ ????????????????"from":?18, ????????????????"to":?28, ????????????????"include_lower":?true, ????????????????"include_upper":?true ????????????} ????????} |
部分匹配
可以發現,以上提出的搜索查詢方式都是針對倒排索引整個詞的操作。即根據詞項在倒排索引中進行匹配查找。也就是說只能查找倒排索引中存在的詞,最小的單元為單個詞。
但如果想匹配倒排索引中存在詞項一部分,?如搜索Java的時候,也希望把JavaScript查出來。這個時候怎么辦呢?這個便是接下來要解釋的內容--部分匹配。
?部分匹配?允許用戶指定查找詞的一部分并找出所有包含這部分片段的結果。默認狀態下,?部分匹配默認不做相關度評分計算,它只是將所有匹配的文檔返回。部分匹配有三種方式,這三種方式也不會對搜索詞進行分詞:
-
前綴查詢
-
通配符查詢
-
正則表達式查詢
| 不會在搜索之前分析查詢字符串,它假定傳入前綴就正是要查找的前綴。 | "prefix":?{"postcode":?"W1"} |
| 使用標準的?shell?通配符查詢:? | "wildcard":?{ ????????????"postcode":?"W?F*HW"?, ????????????"postcode":?"W[0-9].+"?} |
| 正則式 | {?"regexp":?{?"title":?"br.*"?}} |
復合搜索
復合搜索是Elasticsearch中最強大的搜索方式之一,它允許用戶組合多種查詢條件,實現復雜的搜索需求。在Elasticsearch中,復合搜索主要通過bool
查詢實現。bool
查詢可以利用邏輯關系(如and
、or
、not
)組合多個其他的查詢,從而構建出復雜的查詢條件。
除了bool
查詢,Elasticsearch還提供了其他一些復合查詢方式,如filter
查詢、join
查詢等。這些查詢方式可以進一步擴展復合搜索的能力,滿足更復雜的搜索需求。
bool
?過濾器一般由以下三部分組成:
{"bool" : {"must" : [],"should" : [],"must_not" : []}
}
| ?必須?匹配這些條件才能被包含進來。 |
| ?必須不?匹配這些條件才能被包含進來。 |
| 如果滿足這些語句中的任意語句,將增加? |
過濾
過濾和搜索不同,過濾不需要談論相關性或得分。過濾得到的結果:?非是即否。它簡單的對文檔包括或排除處理。fliter可以單獨使用,也可以結合bool復合搜索來實現功能更強大的操作。
Elasticsearch?會在運行過濾查詢時執行多個操作,如執行下面語句時,Elasticsearch行為包含4步:
{ "filter":{"term":{"age": [3,63]},"term":{"price": 30}}
}
-
查找匹配文檔.
term
?查詢在倒排索引中查找,獲取包含該?term?的所有文檔。
2. 創建?bitset.
過濾器會創建一個?bitset?(一個包含?0?和?1?的數組),它描述了哪個文檔會包含該?term?。匹配文檔的標志位是?1?。如有四個文檔,執行完"term":{"age":?[3,63]}語句之后,會得到一個bitset?的值:?[1,0,0,0]
?。
3. 迭代?bitset(s)
一旦為每個查詢生成了?bitsets?,Elasticsearch?就會循環迭代?bitsets?從而找到滿足所有過濾條件的匹配文檔的集合。一般來說先迭代稀疏的?bitset?(因為它可以排除掉大量的文檔)。
4. 增量使用計數.
Elasticsearch?能夠緩存過濾查詢從而獲取更快的訪問,而且過濾查詢也不會計算相關行。因此,filter速度要快于query。
總結
本文先介紹了相關性的知識,然后從全文搜?索,詞項搜索,復合搜索三方面來介紹了ES搜索的常見場景和操作。最后介紹了與搜索對應的過濾操作。
本文的內容意在梳理ES搜索操作,并未細究背后的原理,如相關性算法等。后續如果有需要會補充。當然,在實際應用中,要綜合考慮具體場景來選擇相應的搜索方式。
參考文檔
https://www.cnblogs.com/qdhxhz/p/11493677.html
Elasticsearch 7.x文檔檢索的三大策略:全文搜索、詞項搜索與復合搜索-百度開發者中心