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