ElasticSearch - function_score 簡介

古古

2018/07/04


function_score 內容較多,此篇主要是介紹 function_score 的基本概念

具體實例請參考以下連接

ElasticSearch - function_score(field_value_factor 具體實例)

ElasticSearch - function_score(weight 具體實例)

ElasticSearch - function_score(random_score 具體實例)

ElasticSearch - function_score(衰減函數 linear、exp、gauss 具體實例)

  • 在使用 ES 進行全文搜索時,搜索結果默認會以文檔的相關度進行排序,而這個 “文檔的相關度”,是可以透過 function_score 自己定義的,也就是說我們可以透過使用 function_score,來控制 “怎麼樣的文檔相關度更高” 這件事

    • function_score 是專門用於處理文檔 _score 的 DSL,它允許爲每個主查詢 query 匹配的文檔應用加強函數, 以達到改變原始查詢評分 score 的目的
    • function_score 會在主查詢 query 結束後對每一個匹配的文檔進行一系列的重打分操作,能夠對多個字段一起進行綜合評估,且能夠使用 filter 將結果劃分爲多個子集(每個特性一個filter),並爲每個子集使用不同的加強函數
  • function_score 提供了幾種加強 _score 計算的函數

    • weight : 設置一個簡單而不被規範化的權重提升值
      • weight 加強函數 和 boost 參數 類似,可以用於任何查詢,不過有一點差別是 weight 不會被 Lucene normalize 成難以理解的浮點數,而是直接被應用(boost 會被 normalize)
      • 例如當 weight 爲 2 時,最終結果爲 new_score = old_score * 2
    • field_value_factor : 將某個字段的值乘上 old_score
      • 像是將 字段 shareCount 或是 字段 likeCount 作爲考慮因素,new_score = old_score * 那個文檔的 likeCount 的值
    • random_score : 爲每個用戶都使用一個不同的隨機評分對結果排序,但對某一具體用戶來說,看到的順序始終是一致的
    • 衰減函數 (linear、exp、guass) : 以某個字段的值為基準,距離某個值越近得分越高
    • script_score : 當需求超出以上範圍時,可以用自定義腳本完全控制評分計算,不過因為還要額外維護腳本不好維護,因此盡量使用 ES 提供的評分函數,需求真的無法滿足再使用 script_score
  • function_scroe其他輔助的參數

    • boost_mode : 決定 old_score 和 加強score 如何合併
      • multiply(默認) : new_score = old_score * 加強score
      • sum : new_score = old_score + 加強score
      • min : old_score 和 加強 score 取較小值,new_score = min(old_score, 加強score)
      • max : old_score 和 加強 score 取較大值,new_score = max(old_score, 加強score)
      • replace : 加強 score 直接替換掉 old_score,new_score = 加強score
    • score_mode : 決定 functions 裡面的加強 score 們怎麼合併,會先合併加強 score 們成一個總加強 score,再使用總加強 score 去和 old_score 做合併,換言之就是會先執行 score_mode,再執行 boost_mode
      • multiply(默認)
      • sum
      • avg
      • first : 使用首個函數(可以有filter,也可以沒有)的結果作為最終結果
      • max
      • min
    • max_boost : 限制加強函數的最大效果,就是限制加強 score 最大能多少,但要注意不會限制 old_score
      • 如果加強 score 超過了 max_boost 限制的值,會把加強 score 的值設成 max_boost 的值
      • 假設加強 score 是5,而 max_boost 是2,因為加強 score 超出了 max_boost 的限制,所以 max_boost 就會把加強 score 改為2
      • 簡單的說,就是 加強score = min(加強score, max_boost)
  • function_score 查詢模板

    • 如果要使用 function_score 改變分數,要使用 function_score 查詢

    • 簡單的說,就是在一個 function_score 內部的 query 的全文搜索得到的 _score 基礎上,給他加上其他字段的評分標準,就能夠得到把 “全文搜索 + 其他字段” 綜合起來評分的效果

    • 單個加強函數的查詢模板

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  //主查詢,查詢完後這裡自己會有一個評分,就是 old_score
                  "query": {.....}, 
      
                  //在 old_score 的基礎上,給他加強其他字段的評分
                  //這裡會產生一個加強 score,如果只有一個加強 function 時,直接將加強函數名寫在 query 下面就可以了
                  "field_value_factor": {...}, 
      
                  //指定用哪種方式結合 old_score 和加強 score 成為 new_score
                  "boost_mode": "multiply", 
      
                  //限制加強 score 的最高分,但是不會限制 old_score
                  "max_boost": 1.5 
              }
          }
      }
      
    • 多個加強函數的查詢模板

      • 如果有多個加強函數,那就要使用functions來包含這些加強函數們,functions是一個數組,裡面放著的是將要被使用的加強函數列表

      • 可以為functions裡的加強函數指定一個filter,這樣做的話,只有在文檔滿足此filter的要求,此filter的加強函數才會應用到文擋上,也可以不指定filter,這樣的話此加強函數就會應用到全部的文擋上

      • 一個文檔可以一次滿足多條加強函數和多個filter,如果一次滿足多個,那麼就會產生多個加強score,因此ES會使用score_mode定義的方式來合併這些加強score們,得到一個總加強score,得到總加強score之後,才會再使用boost_mode定義的方式去和old_score做合併

      • 像是下面的例子,field_value_factor和gauss這兩個加強函數會應用到所有文檔上,而weight只會應用到滿足filter的文檔上,假設有個文檔滿足了filter的條件,那他就會得到3個加強score,這3個加強score會使用sum的方式合併成一個總加強score,然後才和old_score使用multiply的方式合併

        GET mytest/doc/_search
        {
            "query": {
                "function_score": {
                    //主查詢,查詢完後這裡自己會有一個評分,就是 old_score
                    "query": {.....},
        
                    //可以有多個加強函數(或是 filter + 加強函數)
                    //每一個加強函數會產生一個加強 score,因此 functions 會有多個加強 score
                    "functions": [   
                        { "field_value_factor": ... },
                        { "gauss": ... },
                        { "filter": {...}, "weight": ... }
                    ],
        
                    //決定加強 score 們怎麼合併成一個總加強 score
                    "score_mode": "sum",
        
                    //決定總加強 score 怎麼和 old_score 合併
                    "boost_mode": "multiply" 
                }
            }
        }
        

  • 不要執著在調整 function_score 上

    • 文檔相關度的調整非常玄,“最相關的文檔” 是一個難以觸及的模糊概念,每個人對文檔排序有著不同的想法,這很容易使人陷入持續反覆調整,但是確沒有明顯的進展
    • 為了避免跳入這種死循環,在調整 function_score 時,一定要搭配監控用戶操作,才有意義
      • 像是如果返回的文檔是用戶想要的高相關的文檔,那麼用戶就會選擇前 10 個中的一個文檔,得到想要的結果,反之,用戶可能會來回點擊,或是嘗試新的搜索條件
      • 一旦有了這些監控手段,想要調適完美的 function_score 就不是問題
    • 因此調整 function_score 的重點在於,要透過監控用戶、和用戶互動,慢慢去調整我們的搜索條件,而不要妄想一步登天,第一次就把文檔的相關度調整到最好,這幾乎是不可能的,因為,連用戶自己也不知道他自己想要什麼