一起學(xué)Elasticsearch系列-Query DSL
DSL是Domain Specific Language的縮寫,指的是為特定問題領(lǐng)域設(shè)計(jì)的計(jì)算機(jī)語言。這種語言專注于某特定領(lǐng)域的問題解決,因而比通用編程語言更有效率。
在Elasticsearch中,DSL指的是Elasticsearch Query DSL,是一種以JSON形式表示的查詢語言。通過這種語言,用戶可以構(gòu)建復(fù)雜的查詢、排序和過濾數(shù)據(jù)等操作。這些查詢可以是全文搜索、聚合搜索,也可以是結(jié)構(gòu)化的搜索。
一、查詢上下文
搜索是Elasticsearch中最關(guān)鍵和重要的部分,使用query關(guān)鍵字進(jìn)行檢索,更傾向于相關(guān)度搜索,故需要計(jì)算評分。
在查詢上下文中,一個查詢語句表示一個文檔和查詢語句的匹配程度。無論文檔匹配與否,查詢語句總能計(jì)算出一個相關(guān)性分?jǐn)?shù)在_score字段上。
1.相關(guān)度評分:score
相關(guān)度評分用于對搜索結(jié)果排序,評分越高則認(rèn)為其結(jié)果和搜索的預(yù)期值相關(guān)度越高,即越符合搜索預(yù)期值,默認(rèn)情況下評分越高,則結(jié)果越靠前。在7.x之前相關(guān)度評分默認(rèn)使用TF/IDF算法計(jì)算而來,7.x之后默認(rèn)為BM25。
score是根據(jù)各種因素計(jì)算出來的,包括:
- Term Frequency(詞頻):一個詞在文檔中出現(xiàn)的次數(shù)越多,score就越高。
- Inverse Document Frequency(逆文檔頻率):一個詞在所有文檔中出現(xiàn)的次數(shù)越少,score就越高。
- Field Length Norm(字段長度規(guī)范):字段的長度越短,score就越高。
這三個因素共同決定了score的值。然而,你也可以通過設(shè)置自定義評分或者禁用評分來影響score的計(jì)算。
2.TF/IDF & BM25
TF/IDF是一種在信息檢索和文本挖掘中廣泛使用的統(tǒng)計(jì)方法,用于評估一個詞語對于一個文件集或一個語料庫中的一個文件的重要程度。名稱中的TF表示“術(shù)語頻率”,IDF表示“逆向文件頻率”。
- TF (Term Frequency) :這是衡量詞在文檔中出現(xiàn)的頻率。通常來說,一個詞在文檔中出現(xiàn)的次數(shù)越多,其重要性就可能越大。但這并不總是正確的,比如在很多英文文檔中,“the”、“and”等詞出現(xiàn)的頻率非常高,但我們并不能因此認(rèn)為它們就非常重要。因此,需要結(jié)合 IDF 來使用。
- IDF (Inverse Document Frequency) :這是衡量詞是否常見的度量。如果某個詞在許多文檔中都出現(xiàn),那么它可能并不具有區(qū)分性,對于搜索和分類的幫助就不大。例如,每篇英文文章中都會出現(xiàn)的“the”對于區(qū)分文章內(nèi)容就沒有什么幫助。所以,如果一個詞在所有文檔中出現(xiàn)得越多,那么其 IDF 值就會越小,相反,如果一個詞很少在文檔中出現(xiàn),那么其 IDF 值就會較大。
TF-IDF 會將這兩個因子結(jié)合起來,為每個詞產(chǎn)生一個權(quán)重。具有較高 TF-IDF 分?jǐn)?shù)的詞被認(rèn)為在文檔中更重要。通過這種方式,ES 能夠提供相關(guān)性排序,使得包含用戶查詢詞匯的最相關(guān)文檔排在搜索結(jié)果的前面。
BM25是一種更先進(jìn)的排名函數(shù),也是基于TF/IDF的一種改進(jìn)型方法。它引入了兩個新概念:
- 文檔長度歸一化:長文檔可能會有更多的關(guān)鍵詞,但這并不意味著它與查詢更相關(guān)。BM25通過調(diào)整文檔長度來解決這個問題。
- 飽和度:在TF/IDF中,詞項(xiàng)的出現(xiàn)頻率越高,其重要性就越大。然而在實(shí)踐中,一旦一個詞在文檔中出現(xiàn)過,再次出現(xiàn)時增加的相關(guān)性可能會降低。BM25通過設(shè)置一個飽和點(diǎn)來解決這個問題,超過這個點(diǎn),詞的權(quán)重增加就會變得不那么敏感。
總結(jié)而言,BM25是TF/IDF的改進(jìn)版,通過文檔長度歸一化和頻率飽和度控制來優(yōu)化搜索結(jié)果。
3.源數(shù)據(jù):source
_source字段包含索引時原始的JSON文檔內(nèi)容,字段本身不建立索引(因此無法進(jìn)行搜索),但是會被存儲,所以當(dāng)執(zhí)行獲取請求是可以返回_source字段。
雖然很方便,但是_source字段的確會對索引產(chǎn)生存儲開銷,你可以通過關(guān)閉_source字段來節(jié)省空間,但這通常不建議,因?yàn)橛辛嗽紨?shù)據(jù),我們可以對數(shù)據(jù)進(jìn)行重新索引,并且在獲取數(shù)據(jù)時也更加靈活。
如果你禁用了_source字段,那么會有以下幾個影響:
- 無法獲取原始數(shù)據(jù):當(dāng)你查詢某個文檔時,你將無法獲取到原始的_source字段內(nèi)容,因?yàn)樗鼪]有被存儲在Elasticsearch中。
- 更新和重新索引的問題:如果你想更新文檔或者執(zhí)行重新索引操作,可能會遇到問題,因?yàn)檫@兩種操作都需要原始的_source字段。
- 腳本字段和某些Aggregations可能受到影響:如果你正在使用腳本字段或者依賴_source字段的Aggregations,那么禁用_source可能導(dǎo)致這些特性出問題。
下面是一些使用_source字段的例子:
(1) 在索引文檔時啟用/禁用_source:
PUT my_index
{
"mappings": {
"_source": {
"enabled": false
},
"properties": {
"field1": { "type": "text" }
}
}
}
在這個例子中,新創(chuàng)建的my_index索引將不會存儲_source字段。
(2) 獲取文檔的_source字段:
GET /my_index/_doc/1
返回的結(jié)果中會包含_source字段。
(3) 在獲取文檔時只獲取_source字段中特定的字段:
GET /my_index/_doc/1?_source=field1,field2
在這個例子中,返回的_source字段只包含field1和field2。
注意:_source字段并不用于搜索,禁用_source字段不會影響你的搜索結(jié)果。
二、源數(shù)據(jù)過濾
假設(shè)你的應(yīng)用只需要獲取部分字段(如"name"和"price"),而其他字段(如"desc"和"tags")不經(jīng)常使用或者數(shù)據(jù)量較大,導(dǎo)致傳輸和處理這些額外的數(shù)據(jù)會增加網(wǎng)絡(luò)開銷和處理時間。在這種情況下,通過設(shè)置includes和excludes可以有效地減少每次請求返回的數(shù)據(jù)量,提高效率。
例如:
PUT product
{
"mappings": {
"_source": {
"includes": ["name", "price"],
"excludes": ["desc", "tags"]
}
}
}
- Including:結(jié)果中返回哪些field。
- Excluding:結(jié)果中不要返回哪些field,Excluding優(yōu)先級比Including更高。
需要注意的是,盡管這些設(shè)置會影響搜索結(jié)果中_source字段的內(nèi)容,但并不會改變實(shí)際存儲在Elasticsearch中的數(shù)據(jù)。也就是說,"desc"和"tags"字段仍然會被索引和存儲,只是在獲取源數(shù)據(jù)時不會被返回。
上述這種在mapping中定義的方式不推薦,因?yàn)閙apping不可變。我們可以在查詢過程中指定返回的字段,如下:
GET product/_search
{
"_source": {
"includes": ["owner.*", "name"],
"excludes": ["name", "desc", "price"]
},
"query": {
"match_all": {}
}
}
Elasticsearch的_source字段在查詢時支持使用通配符(wildcards)來包含或排除特定字段。使得能夠更靈活地操縱返回的數(shù)據(jù)。
關(guān)于規(guī)則,可以參考以下幾點(diǎn):
- *:匹配任意字符序列,包括空序列。
- ?:匹配任意單個字符。
- [abc]: 匹配方括號內(nèi)列出的任意單個字符。例如,[abc]將匹配"a", "b", 或 "c"。
請注意,通配符表達(dá)式可能會導(dǎo)致查詢性能下降,特別是在大型索引中,因此應(yīng)謹(jǐn)慎使用。
三、全文檢索
全文檢索是Elasticsearch的核心功能之一,它可以高效地在大量文本數(shù)據(jù)中尋找特定關(guān)鍵詞。
在Elasticsearch中,全文檢索主要依靠兩個步驟:"分析"(Analysis)和"查詢"(Search)。
(1) 分析: 當(dāng)你向Elasticsearch插入一個文檔時,會進(jìn)行"分析"處理,將原始文本數(shù)據(jù)轉(zhuǎn)換成稱為"tokens"或"terms"的小片段。這個過程可能包括如下操作:
- 切分文本(Tokenization)
- 將所有字符轉(zhuǎn)換為小寫(Lowercasing)
- 刪除常見但無重要含義的單詞(Stopwords)
- 提取詞根(Stemming)
(2) 查詢:當(dāng)執(zhí)行全文搜索時,查詢字符串也會經(jīng)過類似的分析過程,然后再與已經(jīng)分析過的數(shù)據(jù)進(jìn)行比對,找出匹配的結(jié)果并返回。
Elasticsearch提供了許多種全文搜索的查詢類型,例如:
- Match Query:最基本的全文搜索查詢。
- Match Phrase Query:用于查找包含特定短語的文檔。
- Multi-Match Query:類似Match Query,但可以在多個字段上進(jìn)行搜索。
- Query String Query:提供了豐富的搜索語法,可以執(zhí)行復(fù)雜的、靈活的全文搜索。
1.match:匹配包含某個term的子句
match 查詢是 Elasticsearch 中的一種全文查詢方式,它包括標(biāo)準(zhǔn)分析和詞項(xiàng)搜索。盡管它可以應(yīng)用于精確字段,但其主要用途是進(jìn)行全文搜索。當(dāng)與全文字段一起使用時,match 查詢可以解析查詢字符串,并執(zhí)行短語查詢或者構(gòu)建一個布爾查詢,這意味著它會考慮字段中的每個單詞。
下面有一個簡單的 match 查詢示例:
GET /_search
{
"query": {
"match": {
"message": "this is a test"
}
}
}
在這個示例中,Elasticsearch 會在 "message" 字段中搜索包含 "this"、"is"、"a" 和 "test" 的文檔。
請注意,match 查詢不僅僅會匹配完全相同的短語,它還可以處理更復(fù)雜的情況,如多個單詞(它會匹配任何一個)、誤拼、同義詞等,這主要取決于你所使用的分析器和搜索設(shè)置。
match 查詢還有一些其他參數(shù),例如:
- operator:定義多個搜索詞之間的關(guān)系,默認(rèn)為 or。如果設(shè)為 and,則返回的文檔必須包含所有搜索詞。
- minimum_should_match:控制返回的文檔應(yīng)至少匹配的搜索詞的數(shù)量或比例。
- fuzziness:允許模糊匹配,可以找到那些拼寫錯誤或接近的詞匯。
2.match_all:匹配所有結(jié)果的子句
match_all是Elasticsearch中的一個查詢類型,用于獲取索引中的所有文檔。
這是一個match_all查詢的基本示例:
{
"query": {
"match_all": {}
}
}
在上述示例中,我們可以看到查詢對象中存在一個"match_all"字段,其值是一個空對象。這表示我們希望匹配所有文檔。
需要注意,由于 match_all 查詢可能返回大量的數(shù)據(jù),所以一般在使用時都會與分頁(pagination)功能結(jié)合起來,這樣可以控制返回結(jié)果的數(shù)量,避免一次性加載過多數(shù)據(jù)導(dǎo)致的性能問題。例如,你可以使用 from 和 size 參數(shù)來限制返回結(jié)果:
GET /_search
{
"query": {
"match_all": {}
},
"from": 10,
"size": 10
}
Elasticsearch的 match_all 查詢是最簡單的查詢,它不需要任何參數(shù),但如果你想為它添加權(quán)重,可以使用 boost 參數(shù)。例如:
GET /_search
{
"query": {
"match_all": { "boost" : 1.2 }
}
}
在上面的查詢中,boost 參數(shù)被設(shè)置為1.2,給匹配到的所有文檔增加了額外的相關(guān)性得分提升。
3.multi_match:多字段條件
multi_match 可以用來在多個字段上進(jìn)行全文搜索。它接受一個查詢字符串和一組需要在其中執(zhí)行查詢的字段列表。
例如:
{
"query": {
"multi_match" : {
"query": "這是測試",
"fields": [ "field1", "field2" ]
}
}
}
在此示例中,查詢字符串"這是測試"將在字段"field1"和"field2"中搜索。
multi_match查詢也支持使用通配符(*)來匹配多個字段:
{
"query": {
"multi_match" : {
"query": "這是測試",
"fields": [ "*_name" ]
}
}
}
在這個例子中,會在所有以"_name"結(jié)尾的字段中進(jìn)行搜索。
此外,multi_match 查詢還支持許多參數(shù),包括:
- type:設(shè)置查詢類型,可選值包括:best_fields, most_fields, cross_fields, phrase, phrase_prefix 等。
例如,“best_fields” 類型會從指定的字段中挑選分?jǐn)?shù)最高的匹配結(jié)果計(jì)算最終得分,而“most_fields” 類型則會在每個字段中都尋找匹配項(xiàng)并將其分?jǐn)?shù)累加起來。
- tie_breaker:當(dāng)一個詞在多個字段中找到時,用于決定最終得分的參數(shù)。
- minimum_should_match:用于控制應(yīng)匹配的最小子句數(shù)。
- operator:主要有兩個操作符 OR 和 AND,默認(rèn)為 OR。
需要注意的是,當(dāng)使用 multi_match 查詢時,如果字段不同,其權(quán)重可能也會不同。你可以通過在字段名后面添加尖括號(^)和權(quán)重值來調(diào)整特定字段的權(quán)重。例如,"fields": [ "name^3", "description" ]表示在"name"字段中的匹配結(jié)果權(quán)重是"description"字段的三倍。
4.match_phrase:短語查詢
match_phrase 用于精確匹配包含指定短語的文檔。match_phrase 查詢需要字段值中的單詞順序與查詢字符串中的單詞順序完全一致。
例如:
GET /_search
{
"query": {
"match_phrase": {
"message": "this is a test"
}
}
}
這個查詢將會找到"message"字段中包含完整短語"this is a test"的所有文檔。
此外,match_phrase 查詢還有一個 slop 參數(shù),可以定義詞組中的詞語可能存在的位置偏移量。例如,如果將 slop 設(shè)置為 1,則查詢 "this is a test" 也可匹配 "this is test a",因?yàn)?"a" 和 "test" 只需移動一個位置即可匹配。
GET /_search
{
"query": {
"match_phrase": {
"query": "this is a test",
"slop": 2
}
}
}
請注意,match_phrase 查詢需要整個短語完全匹配,而不僅僅是查詢中的所有單詞都存在。如果你只是希望所有單詞都存在,而不關(guān)心它們的順序或精確出現(xiàn)方式,那么你應(yīng)該使用 match 查詢。
四、Term Query
精確查詢用于查找包含指定精確值的文檔,而不是執(zhí)行全文搜索。
1.term:匹配和搜索詞項(xiàng)完全相等的結(jié)果
term 查詢主要用于查詢某個字段完全匹配給定值的文檔。這對精確匹配非常有效,例如數(shù)字、布爾值或者字符串。
用法示例:
GET /_search
{
"query": {
"term" : { "user" : "Kimchy" }
}
}
在這個例子中,我們正在搜索"user"字段中完全匹配"Kimchy"的文檔。
需要注意的是,term 查詢對于分析過的字段(例如,文本字段)可能不會像你預(yù)期的那樣工作,因?yàn)樗鼤阉骶_的詞匯項(xiàng),而不是單詞。如果你想要對文本字段進(jìn)行全文搜素,應(yīng)該使用 match 查詢。
另外一個需要注意的點(diǎn)就是 term 查詢對大小寫敏感,所以 "Kimchy" 和 "kimchy" 是兩個不同的詞條。
2.term和match_phrase的區(qū)別
term 查詢和 match_phrase 查詢是 Elasticsearch 提供的兩種查詢方式,它們都用于查找文檔,但主要的區(qū)別在于如何解析查詢字符串以及匹配的精確度。
- term:這個查詢做的是精確匹配。當(dāng)你使用term查詢時,Elasticsearch會查找完全等于你指定的詞匯的文檔。例如,如果你搜索term "apple",那么只有包含完全為"apple"的文檔會被匹配到,而包含"apples"或"APPLE"的文檔則不會被匹配到。因此,term查詢對大小寫敏感,且不會進(jìn)行任何形式的分析(如停用詞移除、詞干提取等)。
- match_phrase:這個查詢是用來匹配一系列詞匯或者短語的。match_phrase查詢會保證你查詢的詞匯必須以你提供的順序完全匹配。比如,如果你使用match_phrase查詢 "quick brown fox",那么只有包含這個完整短語的文檔才會被匹配到,單獨(dú)包含"quick"、"brown"或者"fox"的文檔則不會被匹配到。此外,與term查詢不同,match_phrase查詢會進(jìn)行文本分析,這意味著它會考慮詞匯的大小寫、復(fù)數(shù)形式等。
總結(jié)來說,term查詢更適合精確匹配,而match_phrase查詢更適合短語匹配。但是,match_phrase并不能100%保證精確匹配,因?yàn)樗鼤幚砗涂紤]文本的各種變體(比如,大小寫、單復(fù)數(shù)形式等)。
3.terms:匹配和搜索詞項(xiàng)列表中任意項(xiàng)匹配的結(jié)果
terms 查詢用于匹配指定字段中包含一個或多個值的文檔。這是一個精確匹配查詢,不會像全文查詢那樣對查詢字符串進(jìn)行分析。
假設(shè)你有一個 "user" 的字段,并且你想找到該字段值為 "John" 或者 "Jane" 的所有文檔,你可以使用 terms 查詢:
GET /_search
{
"query": {
"terms" : {
"user" : ["John", "Jane"],
"boost" : 1.0
}
}
}
上面的查詢將返回所有"user" 字段等于 "John" 或者 "Jane" 的文檔。
其中boost 參數(shù)用于增加或減少特定查詢的相對權(quán)重。它將改變查詢結(jié)果的相關(guān)性分?jǐn)?shù)(_score),以影響最終結(jié)果的排名。
例如,在上述 terms 查詢中,boost 參數(shù)被設(shè)置為 1.0。這意味著如果字段 "user" 的值包含 "John" 或 "Jane",那么其相關(guān)性分?jǐn)?shù)(_score)就會乘以 1.0。因此,這個設(shè)置實(shí)際上并沒有改變?nèi)魏螙|西,因?yàn)槌艘?1 不會改變原始分?jǐn)?shù)。但是,如果你將 boost 參數(shù)設(shè)置為大于 1 的數(shù),那么匹配的文檔的 _score 將會提高,反之則會降低。
五、Range:范圍查找
Range查詢允許我們查找某個范圍內(nèi)的值。假設(shè)我們有一個商品表,其中有商品價格字段,我們可以用range查詢來查找價格在一定范圍內(nèi)的商品。
以下是一個基礎(chǔ)的范圍查詢的例子:
GET /products/_search
{
"query": {
"range" : {
"price" : {
"gte" : 10,
"lte" : 20,
"boost" : 2.0
}
}
}
}
在這個例子中,我們正在查詢價格大于或等于(gte)10且小于或等于(lte)20的所有商品。"boost"參數(shù)表示增加該查詢的重要性。
Range查詢支持以下參數(shù):
- gte:大于或等于。
- lte:小于或等于。
- gt:大于。
- lt:小于。
- boost:增加查詢的重要性。
此外,對于日期類型的字段,你還可以使用如下方式進(jìn)行范圍查詢:
{
"query": {
"range" : {
"timestamp" : {
"gte" : "now-1d/d",
"lt" : "now/d"
}
}
}
}
在上述查詢中,我們正在查找過去24小時內(nèi)的數(shù)據(jù)。"now-1d/d"表示從現(xiàn)在算起的一天前,而"now/d"表示當(dāng)前時間。
六、Filter
過濾器(Filter)是用于篩選數(shù)據(jù)的一種工具。過濾器和查詢(query)相似,但有幾個重要的區(qū)別:
- 過濾不關(guān)心文檔的相關(guān)度得分(relevance score):查詢會為每個匹配的文檔計(jì)算一個相關(guān)度得分,以決定返回結(jié)果的排序。相比之下,過濾器只關(guān)心文檔是否匹配 - 沒有“部分匹配”,只有“匹配”或“不匹配”。
- 過濾器可以被緩存:由于過濾器不需要計(jì)算得分,因此它們的結(jié)果可以被緩存起來用于之后的搜索請求,這可以大大提高性能。
常見的過濾器類型包括:term、terms、range、bool、match_all 等。例如,范圍過濾器 range 可以用于查找數(shù)字或日期字段在指定范圍內(nèi)的文檔;布爾過濾器 bool 則允許你組合多個過濾器,并定義它們?nèi)绾位ハ嘟换ァ?/p>
使用過濾器時,通常會把它們放在 bool 查詢的 filter 子句中。例如:
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" }},
{ "range": { "age": { "gte": 30, "lte": 40 }}}
]
}
}
}
這個查詢會返回所有“狀態(tài)為 active 并且年齡在 30 到 40 之間”的文檔,而不會考慮它們的相關(guān)度得分。
Filter緩存機(jī)制
在 Elasticsearch 中,過濾查詢結(jié)果的緩存機(jī)制是非常重要的一個性能優(yōu)化手段。由于過濾器(filter)只關(guān)心是否匹配,而不關(guān)心評分 (_score),因此它們的結(jié)果可以被緩存以提高性能。
每次 filter 查詢執(zhí)行時,Elasticsearch 都會生成一個名為 "bitset" 的數(shù)據(jù)結(jié)構(gòu),其中每個文檔都對應(yīng)一個位(0 或 1),表示這個文檔是否與 filter 匹配。這個 bitset 就是被存儲在緩存中的部分。
如果相同的 filter 查詢再次執(zhí)行,Elasticsearch 可以直接從緩存中獲取這個 bitset,而不需要再次遍歷所有的文檔來找出哪些文檔符合這個 filter。這大大提高了查詢速度,并減少了 CPU 使用。
這種緩存策略特別適合那些重復(fù)查詢的場景,例如用戶界面的過濾器和類似的功能,因?yàn)樗麄兺ǔa(chǎn)生很多相同的 filter 查詢。
然而,值得注意的是,雖然這種緩存可以顯著改善查詢性能,但也會占用內(nèi)存空間。如果你有很多唯一的過濾條件,那么過濾器緩存可能會變得很大,從而導(dǎo)致內(nèi)存問題。這就需要你對使用的過濾器進(jìn)行適當(dāng)?shù)墓芾砗拖拗啤?/p>
Filter緩存功能會遵循以下原則:
- 同一Filter的多次應(yīng)用:如果在后續(xù)查詢中有多次使用相同的Filter,則ES會把第一次查詢的結(jié)果儲存在緩存中,后續(xù)的查詢將直接從緩存中獲取結(jié)果,而不再做任何磁盤I/O或者其他計(jì)算。
- 根據(jù)需求清理緩存:ES會根據(jù)內(nèi)存使用情況自動清理緩存,當(dāng)然你也可以手動清空緩存。但這并不意味著我們無限制地依賴Filter緩存,大量的緩存可能導(dǎo)致更重的GC壓力。
- 不緩存復(fù)雜查詢:一些查詢條件較復(fù)雜的過濾器可能不會被緩存,比如script filter、geo filter等。這是因?yàn)檫@些過濾器本身的構(gòu)建和維護(hù)成本可能就超過了查詢的計(jì)算成本。
ES的Filter緩存機(jī)制可以大大提高查詢效率,但如果不慎用,比如緩存過多或者不適合緩存的查詢,可能會對性能產(chǎn)生負(fù)面影響。因此,在設(shè)計(jì)和優(yōu)化ES查詢時,應(yīng)當(dāng)充分考慮Filter的使用和緩存策略。
七、Bool Query
Bool Query(組合查詢)可以組合多個查詢條件,bool查詢也是采用more_matches_is_better的機(jī)制,因此滿足must和should子句的文檔將會合并起來計(jì)算分值。
boost和minumum_should_match是參數(shù),其他四個都是查詢子句。
- must:必須滿足子句(查詢)必須出現(xiàn)在匹配的文檔中,并將有助于得分。
- filter:過濾器不計(jì)算相關(guān)度分?jǐn)?shù)。
- should:滿足 or子句(查詢)應(yīng)出現(xiàn)在匹配的文檔中。
- must_not:必須不滿足,不計(jì)算相關(guān)度分?jǐn)?shù) ,not子句(查詢)不得出現(xiàn)在匹配的文檔中。子句在過濾器上下文中執(zhí)行,這意味著計(jì)分被忽略,并且子句被視為用于緩存。
例子1:下面的語句表示:包含"xiaomi"或"phone" 并且包含"shouji"的文檔例子:
GET product/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "xiaomi phone"
}
},
{
"match_phrase": {
"desc": "shouji"
}
}
]
}
}
}
1.should與must或filter一起使用
當(dāng) should 子句與 must 或 filter 子句一起使用時,這時候需要注意了。
只要滿足了 must 或 filter 的條件,should 子句就不再是必須的。換句話說,如果存在一個或者多個 must 或 filter 子句,那么 should 子句的條件會被視為可選。
然而,如果 should 子句與 must_not 子句單獨(dú)使用(也就是沒有 must 或 filter),則至少需要滿足一個 should 子句的條件。
這里有一個例子來說明:
GET /_search
{
"query": {
"bool": {
"must": [
{ "term": { "user": "kimchy" }}
],
"filter": [
{ "term": { "tag": "tech" }}
],
"should": [
{ "term": { "tag": "wow" }},
{ "term": { "tag": "elasticsearch" }}
]
}
}
}
在這個查詢中,must 和 filter 子句的條件是必須滿足的,而 should 子句的條件則是可選的。如果匹配的文檔同時滿足 should 子句的條件,那么它們的得分將會更高。
那如果我們一起使用的時候想讓should滿足該怎么辦?這時候minimum_should_match 參數(shù)就派上用場了。
2.minimum_should_match
minimum_should_match參數(shù)定義了在 should 子句中至少需要滿足多少條件。
例如,如果你有5個 should 子句并且設(shè)置了 "minimum_should_match": 3,那么任何匹配至少三個 should 子句的文檔都會被返回。
這個參數(shù)可以接收絕對數(shù)值(如 2)、百分比(如 30%)、和組合(如 3<90% 表示至少匹配3個或者90%,取其中較大的那個)等不同類型的值。
注意:如果 bool 查詢中只有 should 子句(沒有 must 或 filter),那么默認(rèn)情況下至少需要匹配一個 should 條件,也就是minimum_should_match默認(rèn)值是1,除非 minimum_should_match 明確設(shè)定為其他值。如果包含 must 或 filter的情況下minimum_should_match默認(rèn)值 0。
所以我們可以在包含must 或 filter的情況下,設(shè)置minimum_should_match值來滿足should子句中的條件。