有一種相似度匹配需求,需要以匹配到的標籤個數優先,這種情況就需要用到自定義查詢語句。
先上程式碼,這裡我用的是PHP的陣列結構,最終提交的時候是會轉成json格式的,暫且不表:
'query' => [
'script_score' => [
"query" => [],
'script' => [
'source' => '
def matches = 0;
for (t in params.tags) {
if(doc["tags"].contains(t)) {
matches += 1;
}
}
return _score * matches * matches;
',
"params" => [
"tags" => $tags,
],
]
],
]
首先最外層的陣列就是我們通常寫的query
語句,放在body
中進行請求的,主要看query
裡面的結構,這種需要自定義指令碼處理評分的,query
中只放了一個script_score
:
script_score
包含了兩個部分,一部分是query
,另外一部分是自定義的script
,這裡面的query
,就是正常原本寫在外層的query
中的查詢結構,原本怎麼寫還是怎麼寫,比如這裡面可能還會需要一個標籤匹配的,那麼繼續加一個terms
來查詢。
然後來看script
部分,這裡面又分為兩個東西:
- source 自定義的評分排序指令碼
- params 自定義的評分指令碼引數
首先看params
,這裡我傳遞了$tags
,這是一個標籤陣列,最終會在source
裡進行呼叫,source
部分會放到elasticsearch
中進行編譯,形成類似於函式的東西,然後params
就是一個引數,在source
的程式碼中需要呼叫tags
這個引數,採用params.tags
來進行呼叫。
然後再看source
程式碼部分,這裡面會把搜尋到的結果doc
中的tags
欄位(這doc中的tags
也是一個陣列)與所期望的tags
進行校驗對比,最後得到實際匹配的個數:matches
。
最後看source
中的return部分,這裡會返回評分結果,這裡的_score
是搜尋本身計算的相似度評分,然後這個地方_score * matches * matches
,這裡是採用標籤個數對評分結果進行放大,標籤數匹配越多,自然放大結果就越大。
舉個例子:
匹配文件 | _score | 標籤個數 | 結果分 | 排序位置 |
---|---|---|---|---|
文件A | 40 | 2 | 160 | 2 |
文件B | 30 | 3 | 270 | 1 |
可見最終受到標籤影響更大,實現了標籤結果數優先的排序。
當然,至於放大形式,比如說,評分一樣,以標籤數優先,那麼不用進行標籤平方
處理,另外所期望的放大結果根據具體情況可以自行處理。
另外,在文章末尾帖上elasticsearch
的指令碼語法連結: