今天來了解下 Elasticsearch(以下簡稱 ES) 中的 Query 和 Filter。
在 ES 中,提供了 Query 和 Filter 兩種搜索:
- Query Context:會對搜索進行相關性算分
- Filter Context:不需要相關性算分,能夠利用緩存來獲得更好的性能
舉一個栗子,比如需要搜索一場電影,包含以下信息:
評論中包含了燒腦,評分高於 8 分,同時上映時間在 2010 到 2020 之間。
所以這個搜索包括了三個判斷邏輯,針對三個不同的字段進行查詢,如果需要滿足這樣的查詢需求,在 ES 當中提供了 bool 查詢,一個 bool 查詢可以包含一個或多個查詢字句,支持以下四種查詢:
- must:必須匹配,貢獻算分
- should:選擇性匹配,貢獻算分
- must_not:查詢字句,必須不能匹配
- filter:必須匹配,不貢獻算分
上圖是一個 bool 查詢,是對用戶(user
)進行搜索,城市必須是北京(beijing
) ,性別必須是男(man
),這個采用的是 filter,說明這個對算分是不會產生影響的,must_not
是一個 range 的查詢:年齡大於等於 35 歲;should 里是一個數組,說明這個 should 中可以寫多個條件,只要用戶的名字是這兩個中的一個就是滿足條件的。
其實,bool 查詢的子查詢可以任意順序出現,並且可以嵌套多個查詢。
另外,should 的使用分兩種情況:
- bool 查詢中只包含 should,不包含 must 查詢
- bool 查詢中同時包含 should 和 must 查詢
下面讓我們來看看這兩種情況有何不同?
如果在 bool 查詢中沒有 must 子句,should 中必須至少滿足一條查詢(可以通過 minimum_should_match
來設置滿足條件的個數或者百分比)。
同時包含 should 和 must 時,文檔不必滿足 should 中的條件,但是如果滿足條件,會增加相關性算分。
Filter Context
上面說到了 filter
和 must_not
是不會影響算分的,通過查詢結果中可以看到 _score
都是 0。
Query Context
采用 should 查詢,會進行算分處理,結果如下圖所示:
同時,查詢語句的結構,也會對相關度算分產生影響:
- 同一層級的查詢字段,權重是相同的
- 通過嵌套 bool 查詢,可以改變對算分的影響
Boost & Boosting Query
相關度還可以通過對某個字段設置 boost
的值來進行控制:
- 當 boost > 1 時,打分的相關度相對性提升
- 當 0 < boost < 1 時,打分的權重相對性降低
- 當 boost < 0 時,貢獻負分
或者使用 ES 提供的 Boosting Query 進行查詢:
首先插入幾條數據用於測試:
POST /product/_bulk
{ "index": { "_id": 1 }}
{ "content":"Apple Mac" }
{ "index": { "_id": 2 }}
{ "content":"Apple iPad" }
{ "index": { "_id": 3 }}
{ "content":"Apple Juice" }
如下圖所示,左邊就是一個 Boosting Query,positive 查詢意思是如果 content
中包含 Apple
會按照原始的相關性分數進行打分,negative 查詢則是滿足 positive 查詢同時滿足 negative 查詢(content
中包含 Juice
)的會按照原始的相關性分數乘以 negative_boost
進行打分,negative_boost
是用於降低與 negative 匹配文檔的相關性算分的。
如右圖所示,這個的查詢結果為三條數據,可以發現 Apple Mac
和 Apple iPad
的相關性算分相同,都排在前面,而 Apple Juice
的相關性算分是其他兩個的 0.1 倍,排在最后。
用一個表格來總結下 Query Context 和 Filter Context 的區別:
Context Type | 含義 | 使用方式 |
---|---|---|
Query | 查找與查詢語句最匹配的文檔,對所有文檔進行相關性算分並排序 | query;bool 中的 must 和 should |
Filter | 查找與查詢語句相匹配的文檔 | bool 中的 filter 和 must_not;constant_score 中的 filter |
filter 不需要計算相關性算分,不需要按照相關分數進行排序,同時還有內置的自動 cache 最常使用的 filter 的數據,而 query 相反,需要計算相關性算分,按照分數進行排序,而且無法 cache 結果,因此在某些不需要相關性算分的查詢場景,盡量使用 Filter Context 來讓查詢更加高效。
下圖為 eBay 對於 Filter Context 和 Query Context 的性能比較:
那么 filter 的 cache 是怎么做的呢?
ES 會構建一個文檔匹配過濾器的位集 bitset(用來標識一個文檔對一個 filter 條件是否匹配,如果匹配就是 1,不匹配就是 0),下次再有這個 filter 條件過來的時候就不用重新掃描倒排索引,反復生成 bitset,可以大幅度提升性能,另外當添加或更新文檔時,這個 filter 的位集 bitset 也會更新。
總結
當用戶輸入多個條件進行查詢的時候,可以使用 bool 查詢,在 bool 查詢中,filter
和 must_not
屬於 Filter Context,不會對算分結果產生影響;must
和 should
屬於 Query Context,會對結果算分產生影響。
在 bool 查詢中,查詢結構是對相關性算分有影響的,可以通過嵌套的方式修改不同字段在查詢中的權重以及直接通過指定字段的 boost 值來控制在搜索中的權重,另外使用 Boosting Query 可以提升搜索的精准性,同時也可以將更多的搜索顯示在結果中。
最好的關系就是互相成就,大家的點贊、在看、分享、留言就是我創作的最大動力。
參考
Elastic Stack從入門到實踐
Elasticsearch核心技術與實戰
Elasticsearch頂尖高手系列-快速入門篇
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html