??結(jié)構(gòu)化搜索(Structured search) 是指有關(guān)探詢那些具有內(nèi)在結(jié)構(gòu)數(shù)據(jù)的過(guò)程做瞪。比如日期布朦、時(shí)間和數(shù)字都是結(jié)構(gòu)化的:它們有精確的格式请敦,我們可以對(duì)這些格式進(jìn)行邏輯操作贸营。比較常見(jiàn)的操作包括比較數(shù)字或時(shí)間的范圍贾漏,或判定兩個(gè)值的大小。
1.精確值查找
??當(dāng)使用精確值查找時(shí)翁垂,我們會(huì)使用過(guò)濾器铆遭,由于它不會(huì)計(jì)算相關(guān)度硝桩,所以它的查詢速度相對(duì)較快沿猜。
??我們首先來(lái)看最為常用的 term 查詢, 可以用它處理數(shù)字碗脊、布爾值啼肩、日期以及文本。使用方式如下:
GET /index/type/_search
{
"query" : {
"constant_score" : { //表示該次查詢不計(jì)算相關(guān)度衙伶,常使用它將查詢轉(zhuǎn)化為過(guò)濾
"filter" : {
"term" : {
"filed" : value
}
}
}
}
}
2.bool組合過(guò)濾器
??在第一部分中祈坠,我們講了單個(gè)過(guò)濾器的使用,在日常生活中矢劲,我們經(jīng)常要使用多個(gè)過(guò)濾器來(lái)進(jìn)行篩選結(jié)果赦拘,比如我們要選擇華為品牌,64G芬沉, 價(jià)格在2k-4k之間的手機(jī)躺同,我們要使用組合過(guò)濾器對(duì)結(jié)果進(jìn)行篩選阁猜。
??一個(gè)過(guò)濾器包括三種取值:
(1)must: 表示必須匹配,相當(dāng)于AND蹋艺。
(2)must_not: 表示必須不匹配剃袍,相當(dāng)于NOT。
(3)should:表示任一匹配即可捎谨,相當(dāng)于OR民效。
??使用案例如下(和傳統(tǒng)的sql語(yǔ)句相同,bool過(guò)濾器也支持嵌套):
查詢出產(chǎn)品為三星NOTE7,或者 產(chǎn)品為華為而且價(jià)格為30的記錄
GET /index/type/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"productID" : "三星NOTE7"}},
{ "bool" : {
"must" : [
{ "term" : {"productID" : "華為"}},
{ "term" : {"price" : 30}}
]
}}
],
"minimum_should_match": 1
}
}
}
}
}
??注意:
??1 . bool 查詢會(huì)為每個(gè)文檔計(jì)算相關(guān)度評(píng)分 _score 涛救,再將所有匹配的 must 和 should 語(yǔ)句的分?jǐn)?shù) _score 求和畏邢,最后除以 must 和 should 語(yǔ)句的總數(shù)。其中must_not 語(yǔ)句不會(huì)影響評(píng)分检吆;它的作用只是將不相關(guān)的文檔排除棵红。
??2 .所有 must 語(yǔ)句必須匹配,所有 must_not 語(yǔ)句都必須不匹配咧栗,默認(rèn)情況下逆甜,沒(méi)有 should 語(yǔ)句是必須匹配的,只有一個(gè)例外:那就是當(dāng)沒(méi)有 must 語(yǔ)句的時(shí)候致板,至少有一個(gè) should 語(yǔ)句必須匹配交煞。可以通過(guò)設(shè)置minimum_should_match
參數(shù)來(lái)設(shè)置必須匹配的should語(yǔ)句斟或,他可以使數(shù)字也可以是百分比素征。
3.查詢多個(gè)精確值
??term查詢?cè)谒阉鲉蝹€(gè)值十分有用,但是我們?nèi)绾嗡阉鳚M足多個(gè)條件的值呢萝挤?比如要搜索價(jià)格為20的手機(jī)御毅,相當(dāng)于傳統(tǒng)sql語(yǔ)句中的
in
,當(dāng)然使用bool查詢是一種方式,es給我們提供了terms
查詢怜珍,使用方式如下:
{
"terms" : {
"price" : [20, 30]
}
}
?? 注意:term和terms的操作是包含而非精確相等端蛆,比如我們使用該語(yǔ)句{ "term" : { "tags" : "search" } }
進(jìn)行過(guò)濾時(shí),他會(huì)和以下兩個(gè)文檔同時(shí)匹配:
{ "tags" : ["search"] }
{ "tags" : ["search", "open_source"] }
??如果向要精確匹配酥泛,最好的操作就是增加一個(gè)字段今豆,用以存儲(chǔ)該字段包含項(xiàng)的數(shù)量,用以上為例
{ "tags" : ["search"], "tag_count" : 1 }
{ "tags" : ["search", "open_source"], "tag_count" : 2 }
在搜索條件時(shí)柔袁,將語(yǔ)句修改為bool查詢的must
操作呆躲,讓tags
的值為search
,且tag_count
的值為1
。
"bool" : {
"must" : [
{ "term" : { "tags" : "search" } },
{ "term" : { "tag_count" : 1 } }
]
}
4.范圍
?? 到目前為止捶索,我們都介紹了如何處理相等查詢插掂,對(duì)于數(shù)字過(guò)濾查詢有時(shí)會(huì)更有用,比如在淘寶上搜索手機(jī),可以在首頁(yè)的頭部可以選擇價(jià)格區(qū)間辅甥,用來(lái)更快的找到滿足自己價(jià)位的手機(jī)箩祥。
"range" : {
"price" : {
"gte" : greaterValue,
"lte" : lessValue
}
}
gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)
range查詢不只是能用在數(shù)字上,其他類(lèi)型也可以使用肆氓,比如日期袍祖,字符串
- 日期查詢
eg: 查詢過(guò)去一小時(shí)內(nèi)的所有文檔
"range" : {
"timestamp" : {
"gt" : "now-1h"
}
}
??日期計(jì)算還可以應(yīng)用到具體的時(shí)間,并非只能是now這樣的占位符谢揪,只需要增加一個(gè)雙管符號(hào)||
并緊跟一個(gè)一個(gè)日期表達(dá)式蕉陋。更多詳細(xì)內(nèi)容請(qǐng)看時(shí)間格式參考文檔。
eg: 小于2020-01-07加一個(gè)月也就是 2020-02-07之前拨扶,2020-01-07之后的所有文檔
"range" : {
"timestamp" : {
"gt" : "2020-01-07 00:00:00",
"lt" : "2020-01-07 00:00:00||+1M"
}
}
2.字符串范圍
es在給字符串范圍操作時(shí)凳鬓,是使用的字典序或這字母順序進(jìn)行過(guò)濾的。
eg:查詢文檔字段title中只包含a的文檔患民。
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
注意:數(shù)字和日期范圍的過(guò)濾會(huì)提高搜索性能缩举,但是字符串有可能并非如此,在對(duì)字符串過(guò)濾時(shí)匹颤,es會(huì)對(duì)每個(gè)詞項(xiàng)都進(jìn)行term
過(guò)濾仅孩。
5.關(guān)于緩存
es對(duì)非評(píng)分的行為,會(huì)對(duì)結(jié)果進(jìn)行緩存印蓖。
??1. 查找匹配文檔
??2. 創(chuàng)建bitset對(duì)結(jié)果進(jìn)行緩存,該bit有一個(gè)只包含0和1的數(shù)組辽慕,用來(lái)標(biāo)記那個(gè)文檔匹配。
比如我們有三個(gè)doc
doc1: { price : 20, productid : 1 }
doc2: { price : 30, productid : 2 }
doc3: { price : 40, productid : 3 }
進(jìn)行過(guò)濾查詢 : term: { productid : 3 }
此時(shí)會(huì)創(chuàng)建bitset數(shù)組 [ 0, 0, 1]
??3. 如果有多個(gè)過(guò)濾查詢赦肃,會(huì)迭代bitsets溅蛉,對(duì)結(jié)果集進(jìn)行合并,一般會(huì)先迭代稀疏的bitset他宛,因?yàn)闀?huì)過(guò)濾大量的文檔船侧。
??4. es會(huì)根據(jù)該索引最近的所查詢的歷史狀態(tài),如果該該查詢?cè)谧罱牡?56次查詢被用到過(guò)厅各,則緩存到內(nèi)存中镜撩。如果可以則會(huì)判斷該索引所在的段是否‘足夠大’, 因?yàn)楸容^小的段最后會(huì)被合并讯检,分配緩存會(huì)被浪費(fèi)琐鲁,如果所在的段較小,該緩存會(huì)被忽略人灼。
??注意:
??1. 緩存中的bitset是增量更新的,如果新增加一個(gè)文檔顾翼,并不會(huì)對(duì)所有的bitset緩存進(jìn)行重新計(jì)算投放,而是只會(huì)計(jì)算該新文檔,然后將結(jié)果保存到bitset數(shù)組中适贸。
??2. bitset并不會(huì)依賴(lài)他所在查詢的上下文灸芳,這樣使得緩存可以加速查詢中經(jīng)常使用的部分涝桅,從而降低較少、易變的部分所帶來(lái)的消耗烙样。
如下圖所示:會(huì)查詢?cè)谑占淝覜](méi)有讀過(guò)的冯遂,或者不在收件箱的。其中1 和2的 bitset相同谒获,盡管一個(gè)是 must 蛤肌,一個(gè)是 must_not
"bool": {
"should": [
{ "bool": {
"must": [
{ "term": { "folder": "inbox" }}, 1
{ "term": { "read": false }}
]
}},
{ "bool": {
"must_not": {
"term": { "folder": "inbox" } 2
}
}}
]
}
??3. es會(huì)基于使用頻率自動(dòng)緩存查詢,如果一個(gè)非評(píng)分查詢?cè)谧罱?56次查詢中被使用過(guò)批狱,且所在的段足夠大裸准,才會(huì)緩存。