結(jié)構(gòu)化搜索
在結(jié)構(gòu)化查詢中,我們得到的結(jié)果 總是 非是即否,要么存于集合之中徙邻,要么存在集合之外。結(jié)構(gòu)化查詢不關(guān)心文件的相關(guān)度或評(píng)分畸裳;它簡(jiǎn)單的對(duì)文檔包括或排除處理缰犁。
這在邏輯上是能說通的,因?yàn)橐粋€(gè)數(shù)字不能比其他數(shù)字 更 適合存于某個(gè)相同范圍怖糊。結(jié)果只能是:存于范圍之中帅容,抑或反之。同樣伍伤,對(duì)于結(jié)構(gòu)化文本來說丰嘉,一個(gè)值要么相等,要么不等嚷缭。沒有 更似 這種概念。
精確值查找
當(dāng)進(jìn)行精確值查找時(shí),我們會(huì)使用過濾器(filters)。過濾器很重要简肴,因?yàn)樗鼈儓?zhí)行速度非嘲俨啵快辫狼,不會(huì)計(jì)算相關(guān)度(直接跳過了整個(gè)評(píng)分階段)而且很容易被緩存。請(qǐng)盡可能多的使用過濾式查詢。
term查詢數(shù)字
一般sql表達(dá)
select document from products where price = 20
對(duì)應(yīng)的term搜索
{
"term" : {
"price" : 20
}
}
通常當(dāng)查找一個(gè)精確值的時(shí)候,我們不希望對(duì)查詢進(jìn)行評(píng)分計(jì)算。只希望對(duì)文檔進(jìn)行包括或排除的計(jì)算修噪,所以我們會(huì)使用 constant_score 查詢以非評(píng)分模式來執(zhí)行 term 查詢并以一作為統(tǒng)一評(píng)分脏款。
最終組合的結(jié)果是一個(gè) constant_score 查詢,它包含一個(gè) term 查詢:
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"price" : 20
}
}
}
}
}
1腺占、查詢置于 filter 語句內(nèi)不進(jìn)行評(píng)分或相關(guān)度的計(jì)算积蔚,所以所有的結(jié)果都會(huì)返回一個(gè)默認(rèn)評(píng)分 1
2、我們用 constant_score 將 term 查詢轉(zhuǎn)化成為過濾器
對(duì)于not_analyzed的字段,term查詢不會(huì)對(duì)其進(jìn)行任何分析,比如分詞
組合過濾器
將兩個(gè) term 過濾器置入 bool 過濾器的 should 語句內(nèi),再增加一個(gè)語句處理 NOT 非的條件:
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : 20}},
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}}
],
"must_not" : {
"term" : {"price" : 30}
}
}
}
}
}
}
注意泵肄,我們?nèi)匀恍枰粋€(gè) filtered 查詢將所有的東西包起來冯丙。
查找多個(gè)精確值
term 查詢對(duì)于查找單個(gè)值非常有用,但通常我們可能想搜索多個(gè)值。 不需要使用多個(gè) term 查詢,我們只要用單個(gè) terms 查詢(注意末尾的 s ), terms 查詢好比是 term 查詢的復(fù)數(shù)形式(以英語名詞的單復(fù)數(shù)做比)理郑。
它幾乎與 term 的使用方式一模一樣,與指定單個(gè)價(jià)格不同赚爵,我們只要將 term 字段的值改為數(shù)組即可:
{
"terms" : {
"price" : [20, 30]
}
}
范圍
"range" : {
"price" : {
"gte" : 20,
"lte" : 40
}
}
日期范圍
字符串范圍
按照字典序排列棉胀,但是效率可能比較低下唁奢,最好不用
處理null值
存在查詢
第一件武器就是 exists
存在查詢赐纱,這個(gè)查詢會(huì)返回那些在指定字段有任何值的文檔。
GET /my_index/posts/_search
{
"query" : {
"constant_score" : {
"filter" : {
"exists" : { "field" : "tags" }
}
}
}
}
缺失查詢
這個(gè) missing
查詢本質(zhì)上與 exists
恰好相反:它返回某個(gè)特定 無 值字段的文檔火俄。
GET /my_index/posts/_search
{
"query" : {
"constant_score" : {
"filter": {
"missing" : { "field" : "tags" }
}
}
}
}
緩存
Elasticsearch 的較早版本中犯建,默認(rèn)的行為是緩存一切可以緩存的對(duì)象。這也通常意味著系統(tǒng)緩存 bitsets 太富侵略性,從而因?yàn)榍謇砭彺鎺硇阅軌毫ΣN酢2粌H如此否彩,盡管很多過濾器都很容易被評(píng)價(jià),但本質(zhì)上是慢于緩存的(以及從緩存中復(fù)用)嗦随。緩存這些過濾器的意義不大列荔,因?yàn)榭梢院?jiǎn)單地再次執(zhí)行過濾器。
檢查一個(gè)倒排是非趁赌幔快的贴浙,然后絕大多數(shù)查詢組件卻很少使用它。例如 term 過濾字段 "user_id" :如果有上百萬的用戶署恍,每個(gè)具體的用戶 ID 出現(xiàn)的概率都很小崎溃。那么為這個(gè)過濾器緩存 bitsets 就不是很合算,因?yàn)榫彺娴慕Y(jié)果很可能在重用之前就被剔除了盯质。
這種緩存的擾動(dòng)對(duì)性能有著嚴(yán)重的影響袁串。更嚴(yán)重的是,它讓開發(fā)者難以區(qū)分有良好表現(xiàn)的緩存以及無用緩存呼巷。
為了解決問題囱修,Elasticsearch 會(huì)基于使用頻次自動(dòng)緩存查詢。如果一個(gè)非評(píng)分查詢?cè)谧罱?256 次查詢中被使用過(次數(shù)取決于查詢類型)朵逝,那么這個(gè)查詢就會(huì)作為緩存的候選蔚袍。但是,并不是所有的片段都能保證緩存 bitset 配名。只有那些文檔數(shù)量超過 10,000 (或超過總文檔數(shù)量的 3% )才會(huì)緩存 bitset 啤咽。因?yàn)樾〉钠慰梢院芸斓倪M(jìn)行搜索和合并,這里緩存的意義不大渠脉。
一旦緩存了宇整,非評(píng)分計(jì)算的 bitset 會(huì)一直駐留在緩存中直到它被剔除。剔除規(guī)則是基于 LRU 的:一旦緩存滿了芋膘,最近最少使用的過濾器會(huì)被剔除鳞青。
全文搜索
基于詞項(xiàng)于基于全文
基于詞項(xiàng)的查詢
如 term 或 fuzzy 這樣的底層查詢不需要分析階段,它們對(duì)單個(gè)詞項(xiàng)進(jìn)行操作为朋。用 term 查詢?cè)~項(xiàng) Foo 只要在倒排索引中查找 準(zhǔn)確詞項(xiàng) 臂拓,并且用 TF/IDF 算法為每個(gè)包含該詞項(xiàng)的文檔計(jì)算相關(guān)度評(píng)分 _score 。
記住 term 查詢只對(duì)倒排索引的詞項(xiàng)精確匹配习寸,這點(diǎn)很重要胶惰,它不會(huì)對(duì)詞的多樣性進(jìn)行處理(如, foo 或 FOO )霞溪。這里孵滞,無須考慮詞項(xiàng)是如何存入索引的中捆。如果是將 ["Foo","Bar"] 索引存入一個(gè)不分析的( not_analyzed )包含精確值的字段,或者將 Foo Bar 索引到一個(gè)帶有 whitespace 空格分析器的字段坊饶,兩者的結(jié)果都會(huì)是在倒排索引中有 Foo 和 Bar 這兩個(gè)詞
基于全文的查詢
像 match
或 query_string
這樣的查詢是高層查詢泄伪,它們了解字段映射的信息:
- 如果查詢
日期(date)
或整數(shù)(integer)
字段,它們會(huì)將查詢字符串分別作為日期或整數(shù)對(duì)待匿级。 - 如果查詢一個(gè)(
not_analyzed
)未分析的精確值字符串字段蟋滴,它們會(huì)將整個(gè)查詢字符串作為單個(gè)詞項(xiàng)對(duì)待。 - 但如果要查詢一個(gè)(
analyzed
)已分析的全文字段痘绎,它們會(huì)先將查詢字符串傳遞到一個(gè)合適的分析器脓杉,然后生成一個(gè)供查詢的詞項(xiàng)列表。
一旦組成了詞項(xiàng)列表简逮,這個(gè)查詢會(huì)對(duì)每個(gè)詞項(xiàng)逐一執(zhí)行底層的查詢,再將結(jié)果合并尿赚,然后為每個(gè)文檔生成一個(gè)最終的相關(guān)度評(píng)分散庶。
我們很少直接使用基于詞項(xiàng)的搜索,通常情況下都是對(duì)全文進(jìn)行查詢凌净,而非單個(gè)詞項(xiàng)悲龟,這只需要簡(jiǎn)單的執(zhí)行一個(gè)高層全文查詢(進(jìn)而在高層查詢內(nèi)部會(huì)以基于詞項(xiàng)的底層查詢完成搜索)。
匹配查詢
匹配查詢 match
是個(gè) 核心 查詢冰寻。無論需要查詢什么字段须教, match
查詢都應(yīng)該會(huì)是首選的查詢方式。它是一個(gè)高級(jí) 全文查詢 斩芭,這表示它既能處理全文字段轻腺,又能處理精確字段。
這就是說划乖, match
查詢主要的應(yīng)用場(chǎng)景就是進(jìn)行全文搜索
單個(gè)詞查詢
我們用第一個(gè)示例來解釋使用 match 查詢搜索全文字段中的單個(gè)詞:
GET /my_index/my_type/_search
{
"query": {
"match": {
"title": "QUICK!"
}
}
}
Elasticsearch 執(zhí)行上面這個(gè) match 查詢的步驟是:
檢查字段類型 贬养。
標(biāo)題 title 字段是一個(gè) string 類型( analyzed )已分析的全文字段,這意味著查詢字符串本身也應(yīng)該被分析琴庵。分析查詢字符串 误算。
將查詢的字符串 QUICK! 傳入標(biāo)準(zhǔn)分析器中,輸出的結(jié)果是單個(gè)項(xiàng) quick 迷殿。因?yàn)橹挥幸粋€(gè)單詞項(xiàng)儿礼,所以 match 查詢執(zhí)行的是單個(gè)底層 term 查詢。查找匹配文檔 庆寺。
用 term 查詢?cè)诘古潘饕胁檎?quick 然后獲取一組包含該項(xiàng)的文檔蚊夫,本例的結(jié)果是文檔:1、2 和 3 止邮。為每個(gè)文檔評(píng)分 这橙。
用 term 查詢計(jì)算每個(gè)文檔相關(guān)度評(píng)分 _score 奏窑,這是種將 詞頻(term frequency,即詞 quick 在相關(guān)文檔的 title 字段中出現(xiàn)的頻率)和反向文檔頻率(inverse document frequency屈扎,即詞 quick 在所有文檔的 title 字段中出現(xiàn)的頻率)埃唯,以及字段的長(zhǎng)度(即字段越短相關(guān)度越高)相結(jié)合的計(jì)算方式。
多詞查詢
GET /my_index/my_type/_search
{
"query": {
"match": {
"title": "BROWN DOG!"
}
}
}
match
查詢必須查找兩個(gè)詞( ["brown","dog"]
)鹰晨,它在內(nèi)部實(shí)際上先執(zhí)行兩次 term
查詢墨叛,然后將兩次查詢的結(jié)果合并作為最終結(jié)果輸出。為了做到這點(diǎn)模蜡,它將兩個(gè) term
查詢包入一個(gè) bool
查詢中漠趁,詳細(xì)信息見 布爾查詢。
以上示例告訴我們一個(gè)重要信息:即任何文檔只要 title
字段里包含 指定詞項(xiàng)中的至少一個(gè)詞 就能匹配忍疾,被匹配的詞項(xiàng)越多闯传,文檔就越相關(guān)。
提高精度
用 任意 查詢?cè)~項(xiàng)匹配文檔可能會(huì)導(dǎo)致結(jié)果中出現(xiàn)不相關(guān)的長(zhǎng)尾卤妒。這是種散彈式搜索甥绿。可能我們只想搜索包含 所有 詞項(xiàng)的文檔则披,也就是說共缕,不去匹配 brown OR dog
,而通過匹配 brown AND dog
找到所有文檔士复。
match
查詢還可以接受 operator
操作符作為輸入?yún)?shù)图谷,默認(rèn)情況下該操作符是 or
。我們可以將它修改成 and
讓所有指定詞項(xiàng)都必須匹配阱洪。
控制精度
在 所有 與 任意 間二選一有點(diǎn)過于非黑即白便贵。 如果用戶給定 5 個(gè)查詢?cè)~項(xiàng),想查找只包含其中 4 個(gè)的文檔冗荸,該如何處理嫉沽?將 operator
操作符參數(shù)設(shè)置成 and
只會(huì)將此文檔排除。
有時(shí)候這正是我們期望的俏竞,但在全文搜索的大多數(shù)應(yīng)用場(chǎng)景下绸硕,我們既想包含那些可能相關(guān)的文檔,同時(shí)又排除那些不太相關(guān)的魂毁。換句話說玻佩,我們想要處于中間某種結(jié)果。
match
查詢支持 minimum_should_match
最小匹配參數(shù)席楚, 這讓我們可以指定必須匹配的詞項(xiàng)數(shù)用來表示一個(gè)文檔是否相關(guān)咬崔。我們可以將其設(shè)置為某個(gè)具體數(shù)字,更常用的做法是將其設(shè)置為一個(gè)百分?jǐn)?shù),因?yàn)槲覀儫o法控制用戶搜索時(shí)輸入的單詞數(shù)量垮斯。