因為 elasticsearch 要打很多字,寫文苦手如我決定縮寫它,所以會用 ES 代稱。
今天來說明一下 boolean search;前幾篇的 search query 都只有一個條件,當有多於一個條件的時候,就可以使用 Boolean search 把不同的 query 組合起來。
Boolean query 裡面可由四種不同的子句組成,分別是 must
、 filter
、 must_not
、 should
,使用起來會是這樣(從官網抄來的 query):
POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user.id" : "kimchy" }
},
"filter": {
"term" : { "tags" : "production" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tags" : "env1" } },
{ "term" : { "tags" : "deployed" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
其中 must
和 must_not
蠻好理解的,就是要不要包含這個條件的資料(doc),那為什麼還需要 filter
和 should
呢?
filter
和 should
都是正向表列的;也就是要找出條件是成立的文件, 兩者跟 must
的差別是 filter
不計分、 should
計分但不包含這個條件也沒關係,也就是如果有就加分,沒有也沒關係的意思;另外 must
內如果有多個條件,則是 and
的關係,而 should
內如果有郭的條件,會是 or
的關係。
這邊講的計分是什麼意思呢?
大家應該有注意到在搜尋的結果中,都會有一個欄位是 _score
,判斷這個文件與搜尋字詞的相關性、重要性;在全文搜索中,計分的方式是 boost * tf-idf
, tf-idf 是一個文本處理中計算 token 重要性的指標,這邊不細講指標的計算,但這個指標在 token 出現在一個文本的數量呈正比,同時跟這個 token 出現在全部文本中的數量呈反比。
用白話文一點解釋是這樣的:今天只考量一個文本,一個 token 在一個文本中出現的次數越多,我們會覺得這個 token 的意思跟整個文本的整體會有很強的相關:假設一篇文章出現了很多次 elasticsearch
,那我們應該會認為這篇文章內容應該跟 elasticsearch 很有相關,在搜尋這個 token 的時候,這篇文章應該要被放在最前面。但我們應該要同時考量這個 token 出現在全部文本的次數,如果這個字總體而言使用頻率很高,那在單一篇文章中出現很多次也不是什麼特別的事,相關性分數就會低一點。
如果你想知道 ES 到底是怎麼算出分數的,可以使用 explain
api,它會告訴妳每一個分數的計算過程,使用方式如下:
GET /<index_name>/_explain/<doc_id>
{
<你想要執行的 query >
}
那計分方式中的 boost
又是什麼呢?
boost
是一個常數,預設為 1,可以想像為對比度;因為 tf-idf 算出來是一個浮點數,假設今天文本的分數差異很小,可以用 boost 來調整差異。
minimum_should_match
則是設定 should
的條件如果有多個,最少要 match 幾個,如果 boolean query 內只有一個 should
子句,則這個參數的預設值是 1 反之是 0。
search query 內還有一個 geo query,因為後續 auto-complete 不會使用到,這邊就先跳過了,如果有興趣可以參考官網文件。
下一篇,我們要開始踏入真實世界,並且試著實作 auto-complete 了。