Elasticsearch 按照標籤匹配個數優先排序查詢

kumfo發表於2022-11-22

有一種相似度匹配需求,需要以匹配到的標籤個數優先,這種情況就需要用到自定義查詢語句。

先上程式碼,這裡我用的是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標籤個數結果分排序位置
文件A4021602
文件B3032701

可見最終受到標籤影響更大,實現了標籤結果數優先的排序。

當然,至於放大形式,比如說,評分一樣,以標籤數優先,那麼不用進行標籤平方處理,另外所期望的放大結果根據具體情況可以自行處理。

另外,在文章末尾帖上elasticsearch的指令碼語法連結:

https://www.elastic.co/guide/...

相關文章