Query DSL
"ES提供了基于JSON的查詢DSL,它由兩種語句組成:
- 葉子查詢(Leaf Query):查詢特定字段的特定值,比如match, term, range查詢,這些查詢可以單獨(dú)使用。
- 復(fù)合查詢(Compound Query):復(fù)合查詢包裝其他葉子查詢和復(fù)合查詢,以邏輯運(yùn)算的方式(比如bool,dis_max查詢)連接多個查詢,或更改它們的行為(比如,constant_score查詢)
依據(jù)它們是在查詢上下文(query context)還是過濾上下文(filter context),查詢語句的行為也有所不同。
查詢和過濾上下文
查詢上下文
在查詢上下文解決的是這種問題:“此文檔與此查詢的匹配程度如何?”,除了決定文檔是否匹配外,查詢語句還會計算一個_score字段,表示該文檔相對其他文檔的匹配程度。
位于query參數(shù)下的語句,處于查詢上下文。
過濾查詢
過濾上下文解決的是這種問題:“此文檔是否匹配該查詢”,回答只有是或者否,不會計算相關(guān)性分值。過濾上下文主要用于過濾結(jié)構(gòu)化的數(shù)據(jù),比如:
- 這個時間是否屬于2015-2016年之間
- status字段的值是否是1
ES會緩存經(jīng)常使用的查詢,以提升性能。
位于filter參數(shù)下的語句,處于過濾上下文中。比如在bool查詢中的filter或must_not參數(shù),在constant_score查詢中的filter參數(shù),或filter聚合。
下面的示例展示搜索API中,在查詢上下文和過濾上下文中的語句。這條查詢會匹配滿足下列條件的文檔:
- title字段包含單詞search
- content字段包含單詞elasticsearch
- satus字段指就是published
- publish_date字段的日期大于等于2015.1.1
說明:
- bool和match語句用在查詢上下文中,這意味著他們被用來評估每個文檔的匹配程度(分值)。
- term和range語句用在過濾上下文中,它們會過濾掉不匹配的文檔,但是不會影響匹配文檔的分值
匹配所有
match_all查詢,匹配所有文檔,每個文檔_score值為1:
GET {index}/_search {"query": {"match_all": {}} }與之相反的是match_none,不匹配任何文檔
全文查詢
全文查詢允許你搜索分詞后的文本字段,比如電子郵件的內(nèi)容。包括:
- match :全文查詢的標(biāo)準(zhǔn)方式,包括模糊匹配(fuzzing),短語或鄰近查詢。
- match_phrase :類似match,但只用于精確匹配短語或單詞鄰近匹配
- match_phrase_prefix:同上,但是只對最后一個單詞進(jìn)行通配符搜索
- match_bool_prefix:創(chuàng)建一個bool查詢,對每個詞條創(chuàng)建一個term查詢,最后一個詞條除外,該詞條作為prefix查詢匹配
- multi_match:match查詢的多字段形式
- common詞條查詢:相對專門的查詢,適用于不常用的單詞
- query_string查詢:支持緊湊的Lucene查詢字符串語法,支持在單個查詢字符串中指定AND|OR|NOT邏輯條件和多字段搜索。僅限專業(yè)用戶使用
- simple_query_string查詢:比起query_string語法更簡單,更健壯,適用于普通用戶使用
- intervals查詢:允許對匹配詞條的順序和鄰近度進(jìn)行細(xì)粒度(fine-grained)的控制
match
我們先創(chuàng)建一條文檔:
POST twitter/_doc {"user": "ayhan","post_date": "2009-11-15T14:12:12","message": "let me out from here" }基本用法:
GET twitter/_search {"query": {"match": {"message": "out me" // messag是搜索的字段,值是要查詢的字符串}} }因此上述查詢的結(jié)果是message字段中包含詞條out, 或me的所有文檔。
match查詢會對提供的文本進(jìn)行分詞,并構(gòu)建布爾查詢。邏輯運(yùn)算符operator默認(rèn)是or,我們也可以手動設(shè)為and,來控制布爾語句。
GET twitter/_search {"query": {"match": {"message": {"query": "out me", // 指定查詢字符串"operator": "and" // 指定邏輯運(yùn)算符}}} }這樣查詢的結(jié)果是message字段中同時包含詞條out 和 me的所有文檔,范圍將大大縮小。
除了指定operator,我們還可以指定如下參數(shù):
- analyzer 指定分詞器
- minimum_should_match,沒看懂
- lenient :異常處理,是否忽略由數(shù)據(jù)類型錯誤導(dǎo)致的異常,默認(rèn)false,比如使用文本查詢字符串來查詢數(shù)字字段
- zero_terms_query:零項查詢,指定查詢詞條為空時的行為(比如指定的分詞器移除了所有詞條),其值為:
- none,相當(dāng)于match_none,默認(rèn)值
- all ,相當(dāng)于match_all
- cutoff frequency :指定文檔高低頻的分界線
- synonyms 對于同義詞定義:ny, new york,相當(dāng)于ny OR (new york)
match phrase
短語匹配,示例:
GET twitter/_search {"query": {"match_phrase": {"message": "huawei mate pro" // 查詢message字段包含huawei mate pro的文檔}} }類似match查詢,短語匹配首先也會將查詢字符串解析為詞條列表,然后對這些詞條進(jìn)行搜索。但是只保留同時包含所有詞條,且位置順序與搜索詞條一致,中間不夾雜其他單詞的文檔。
短語匹配是利用倒排索引中的位置信息實(shí)現(xiàn)的。
判斷文檔是否和短語huawei mate pro匹配,要同時滿足如下條件:
- huawei、mate和pro必須全部出現(xiàn)
- mate的位置比huawei大1
- pro的位置比mate大2
multi_match
multi_match基于match查詢,但是支持查詢多個字段:
GET article/_search {"query": {"multi_match": {"query": "hello world", // 查詢字符串"fields": ["title", "content"] // 要查找的字段}} }如果不指定具體字段,將查詢所有字段。multi_match查詢支持match查詢的所有參數(shù)。
通配符
fields參數(shù)可以支持通配符,比如:
"fields": [ "title", "*_name" ]可以查詢title, first_name和last_name字段
字段權(quán)重
可以使用^標(biāo)記,增大個別字段的權(quán)重:
"fields": ["title^3", "content"]如此一來,title字段的權(quán)重3倍于content字段,這將會影響搜索結(jié)果中_score的打分(打分越高,排名越靠前),^標(biāo)記的權(quán)重的值越大,對打分影響越大。
查詢方式
multi_match的查詢方式取決于type參數(shù),默認(rèn)值是best_fields,全部可選項及區(qū)別具體參考官網(wǎng)
best_fields
如果你想搜索多個單詞在某個字段中的最好匹配,best_fields最合適。例如,"huawei mate pro"出現(xiàn)在單個字段中,比"huawei"出現(xiàn)在一個字段,"mate pro"出現(xiàn)在另一個字段更有意義。
best_fields方式為每個字段創(chuàng)建一個match查詢,并包在一個dis_max查詢中,來找到單個最匹配的字段。比如:
GET /_search {"query": {"multi_match" : {"query": "brown fox","type": "best_fields","fields": [ "subject", "message" ],"tie_breaker": 0.3}} }會這樣執(zhí)行:
GET /_search {"query": {"dis_max": {"queries": [{ "match": { "subject": "brown fox" }},{ "match": { "message": "brown fox" }}],"tie_breaker": 0.3}} }打分方式:通常情況下,best_fields使用匹配最好的字段的打分,但是如果指定了tie_breaker參數(shù),則有所不同,具體查看官網(wǎng)。
注意:
best_fiels和most_fields方式都會為每個字段創(chuàng)建一個match查詢,因此operator和minimum_should_match參數(shù)將對每個字段單獨(dú)應(yīng)用,這可能不是你想要的。比如:
GET /_search {"query": {"multi_match" : {"query": "Will Smith","type": "best_fields","fields": [ "first_name", "last_name" ],"operator": "and"}} }將會以這樣的邏輯執(zhí)行:
(+first_name:will +first_name:smith) | (+last_name:will +last_name:smith)也就是說,如果一個文檔要匹配,必須在單個字段中出現(xiàn)查詢的所有詞條。
most_fields
如果查詢的多個字段的文本經(jīng)過分詞處理后(不管以怎樣的方式),包含同樣的文本,那么most_fields方式最合適。比如,主字段的查詢結(jié)果可能包含同義詞,詞干,沒有變音符的詞條等(可以理解為關(guān)聯(lián)性較強(qiáng)的文檔)。第二個字段可能包含原始的查詢詞條(更準(zhǔn)確,但是范圍更小,但是打分高)。通過合并這些字段的打分,我們可以匹配盡可能多的文檔(主字段),但是最接近的結(jié)果又可以獲得優(yōu)先展示(第二個字段)。
如下查詢:
GET /_search {"query": {"multi_match" : {"query": "quick brown fox","type": "most_fields","fields": [ "main_filed", "strict_field" ]}} }將會這樣執(zhí)行:
GET /_search {"query": {"bool": {"should": [{ "match": { "main_filed": "quick brown fox" }},{ "match": { "strict_field": "quick brown fox" }}]}} }打分方式:每個match語句的打分被加總,然后除以match語句的數(shù)量。
cross_fields
cross_fields方式特別適合要匹配多個字段的結(jié)構(gòu)化文檔。比如,要從first_name和last_name字段中查詢"Will Smith",最匹配的應(yīng)該是Will出現(xiàn)firs_name字段,而Smith出現(xiàn)在last_name字段。
一種處理這種查詢的方式是只需要將first_name和last_name索引到一個full_name字段。但是,這只能在索引時操作。而cross_fields方式嘗試在查詢時解決這種問題。它先將查詢字符串分詞為一個個詞條,然后在指定字段中查找每個詞條。
下面的查詢:
GET /_search {"query": {"multi_match" : {"query": "Will Smith","type": "cross_fields","fields": [ "first_name", "last_name" ],"operator": "and"}} }將會這樣執(zhí)行:
+(first_name:will last_name:will) +(first_name:smith last_name:smith)也就是說,一個文檔如果要匹配,所有的詞條必須出現(xiàn)在至少一個字段中。
common
common查詢時可以將停用詞考慮在內(nèi),對于能提高查詢精度,影響查詢結(jié)果的停用詞是不錯的選擇,并且不會犧牲性能。
問題
查詢的每個詞條都有花銷。比如,搜索"The brown fox"將產(chǎn)生3次詞條查詢,也就是"the",“brown”,“fox”,每次查詢都要搜索索引中的所有文檔。對于"the"的查詢很可能會匹配到大量文檔,但是比起另外兩次查詢,"the"對于相關(guān)性的影響要小得多。
之前的方案是,忽略哪些高頻出現(xiàn)的詞條。也就是將"the"作為停用詞對待,這樣不僅能減少索引的大小,還可以較少需要執(zhí)行查詢的詞條的數(shù)量。
這種方案的問題是,盡管停用詞對相關(guān)性的影響很小,但它們?nèi)匀缓苤匾?。如果移除了停用詞,不僅影響查詢的精度(比如,無法區(qū)分"happy"和"not happy"),甚至是丟失查詢結(jié)果("To be or not to be"壓根不會被搜到)。
解決方案
common查詢將要查詢的詞條分為兩組:重要的(比如,低頻詞條)和相對不重要的(比如,像停用詞這樣的高頻詞條)。
首先,查詢能匹配重要詞條的文檔,包含這類詞條的文檔相對較少并且對相關(guān)性影響較大。
然后,對不重要的詞條執(zhí)行第二次查詢,這類詞條在文檔中高頻出現(xiàn)并且對相關(guān)性影響較小。但是,這里不會計算所有匹配文檔的相關(guān)性打分,只計算在第一次查詢中已經(jīng)匹配的文檔。通過這種方式,高頻詞條可以改進(jìn)相關(guān)性計算,卻不用付出過大的性能代價。
如果查詢只包含高頻詞條,那么每次查詢會以AND連接,也就是所有的詞條都需要。盡管單個詞條會匹配到大量文檔,但是詞條的聯(lián)合可以縮小范圍為最相關(guān)的文檔。不過,通過指定minimum_should_match,每次查詢也可以用OR連接,但是這種情況下,需要指定一個足夠大的值。
詞條是分布在高頻組還是低頻組,是基于cutoff_frequency,其可以指定為絕對頻率(>=1),或者是相對頻率(0.0 .. 1.0),高于設(shè)定值的屬于高頻詞條,反之低頻詞條。
注意:common不支持多字段查詢
示例
下面的示例中,文檔頻率大于0.1%的單詞(比如,“this"和"is”)視為common terms
GET /_search {"query": {"common": {"body": {"query": "this is bonsai cool","cutoff_frequency": 0.001}}} }要匹配的詞條數(shù)可以通過以下參數(shù)控制:
- minimum_should_match 指定低頻詞至少要匹配幾個
- high_freq 指定高頻詞至少匹配幾個
- low_freq 指定低頻詞至少匹配幾個
- low_freq_operator(默認(rèn)"or")
- high_freq_oprator(默認(rèn)"or")
對于低頻詞條,設(shè)置low_freq_operator為and,來要求所有詞條都滿足:
GET /_search {"query": {"common": {"body": { // 查詢body字段"query": "nelly the elephant as a cartoon","cutoff_frequency": 0.001,"low_freq_operator": "and"}}} }以上相當(dāng)于:
GET /_search {"query": {"bool": {"must": [{ "term": { "body": "nelly"}},{ "term": { "body": "elephant"}},{ "term": { "body": "cartoon"}}],"should": [{ "term": { "body": "the"}},{ "term": { "body": "as"}},{ "term": { "body": "a"}}]}} }也可以通過minimum_should_match參數(shù)指定低頻詞(重要詞)出現(xiàn)的最小百分比,比如:
GET /_search {"query": {"common": {"body": {"query": "nelly the elephant as a cartoon","cutoff_frequency": 0.001,"minimum_should_match": 2}}} }以上約等于:
GET /_search {"query": {"bool": {"must": {"bool": {"should": [{ "term": { "body": "nelly"}},{ "term": { "body": "elephant"}},{ "term": { "body": "cartoon"}}],"minimum_should_match": 2 // nelly、elephant、cartoon中至少匹配到兩個,才影響相關(guān)性}},"should": [{ "term": { "body": "the"}},{ "term": { "body": "as"}},{ "term": { "body": "a"}}]}} }如果想同時指定低頻詞和高頻詞的匹配數(shù),可以指定minimum_should_match的low_freq和high_freq:
GET /_search {"query": {"common": {"body": {"query": "nelly the elephant not as a cartoon","cutoff_frequency": 0.001,"minimum_should_match": {"low_freq" : 2,"high_freq" : 3}}}} }以上相當(dāng)于:
GET /_search {"query": {"bool": {"must": {"bool": {"should": [{ "term": { "body": "nelly"}},{ "term": { "body": "elephant"}},{ "term": { "body": "cartoon"}}],"minimum_should_match": 2 // 以上3個詞條至少匹配兩個}},"should": {"bool": {"should": [{ "term": { "body": "the"}},{ "term": { "body": "not"}},{ "term": { "body": "as"}},{ "term": { "body": "a"}}],"minimum_should_match": 3 // 以上四個詞條至少匹配3個}}}} }如果為高頻詞指定了minimum_should_match,并且查詢字符串中只有高頻詞時:
GET /_search {"query": {"common": {"body": {"query": "how not to be","cutoff_frequency": 0.001,"minimum_should_match": {"low_freq" : 2,"high_freq" : 3}}}} }以上相當(dāng)于:
GET /_search {"query": {"bool": {"should": [{ "term": { "body": "how"}},{ "term": { "body": "not"}},{ "term": { "body": "to"}},{ "term": { "body": "be"}}],"minimum_should_match": "3<50%" // 老實(shí)說,我也沒看明白}} }最后,common查詢也支持boost和analyzer參數(shù)。
simple_query_string
term查詢
term查詢是一種適用于結(jié)構(gòu)化數(shù)據(jù)的精確查詢,它不會像全文檢索一樣對搜索做分詞。結(jié)構(gòu)化數(shù)據(jù)包括日期,IP,價格,商品條碼等。注意:要避免對text字段使用term查詢(text字段的內(nèi)容經(jīng)過語義處理,可能發(fā)生變化)。
term
GET /_search {"query": {"term": {"user": { // 要查找的字段"value": "Kimchy", // 該字段要精確包含的值"boost": 1.0}}} }terms
同term,但是可以搜索多個值:
GET /_search {"query" : {"terms" : {"user" : ["foo", "bar"],"boost" : 1.0}} }以上只要user字段包含foo, 或者bar即可(Foo, bars不算)
復(fù)合查詢
constant_score
包裝一個過濾查詢,所有匹配的文檔會給予相同的打分1.0(因?yàn)檫^濾上下文不計算打分)
GET /_search {"query": {"constant_score" : {"filter" : {"term" : { "user" : "kimchy"}},"boost" : 1.2}} }bool
匹配布爾連接的多個查詢,類別如下:
- must 必須匹配,影響打分()
- filter 必須匹配,但是忽略打分(0分)
- should 應(yīng)該匹配,影響打分
- must_not 不能匹配(語句會在過濾上下文中執(zhí)行,因此打分也會忽略(0分))類似于exclude
注意:must和should的打分會累加為匹配文檔最終打分
POST _search {"query": {"bool" : {"must" : {"term" : { "user" : "kimchy" }},"filter": {"term" : { "tag" : "tech" }},"must_not" : {"range" : {"age" : { "gte" : 10, "lte" : 20 }}},"should" : [{ "term" : { "tag" : "wow" } },{ "term" : { "tag" : "elasticsearch" } }],"minimum_should_match" : 1, // 是否是針對should生效?"boost" : 1.0}} }另外,must, filter, must_not也可以使用列表的形式指定多個條件。
bool查詢中有一個match_all查詢,會給所有文檔打1.0分
GET _search {"query": {"bool": {"must": {"match_all": {}},"filter": {"term": {"status": "active"}}}} }另外,constant_score和match_all是同樣的效果:
GET _search {"query": {"constant_score": {"filter": {"term": {"status": "active"}}}} }dis_max
function_score
boosting
權(quán)重查詢,返回能夠匹配positive的文檔,并減小匹配negative文檔的打分
GET /_search {"query": {"boosting" : {"positive" : {"term" : {"text" : "apple"}},"negative" : {"term" : {"text" : "pie tart fruit crumble tree"}},"negative_boost" : 0.5}} }總結(jié)
- 上一篇: 操作系统已经向SQL Server 返回
- 下一篇: UML类图操作(一)