ElasticSearch - function_score(field_value_factor 具體實例)

古古

2018/07/05


閱讀本文需要先了解 function_score 的相關知識,請看 ElasticSearch - function_score 簡介

  • 首先準備數據和索引,在ES插入三筆數據,其中 title 是 text 類型,like 是 integer 類型(代表點贊量)

    { "title": "ES 入門", "like": 2 }
    { "title": "ES 進階", "like": 5 }
    { "title": "ES 最高難度", "like": 10 }
    
  • 先使用一般的 query,查看普通的查詢的評分會是如何

    GET mytest/doc/_search
    {
        "query": {
            "match": {
                "title": "ES"
            }
        }
    }
    
    "hits": [
        {
            "_score": 0.2876821,
            "_source": { "title": "ES 入門", "like": 2 }
        },
        {
            "_score": 0.20309238,
            "_source": { "title": "ES 進階", "like": 5 }
        },
        {
            "_score": 0.16540512,
            "_source": { "title": "ES 最高難度", "like": 10 }
        }
    ]
    
  • 使用 function_score 的 field_value_factor 改變 _score,將 old_score 乘上 like 的值

    • 本來 “ES 最高難度” 的 score 是0.16540512,經過 field_value_factor 的改變,乘上了那個文檔中的like值(10)之後,新的 score 變為 1.6540513

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match": {
                          "title": "ES"
                      }
                  },
                  "field_value_factor": {
                      "field": "like"
                  }
              }
          }
      }
      
      "hits": [
          {
              "_score": 1.6540513, //原本是0.16540512
              "_source": { "title": "ES 最高難度", "like": 10 }
          },
          {
              "_score": 1.0154619, //原本是0.20309238
              "_source": { "title": "ES 進階", "like": 5 }
          },
          {
              "_score": 0.5753642, //原本是0.2876821
              "_source": { "title": "ES 入門", "like": 2 }
          }
      ]
      
  • 加上 max_boost,限制 field_value_factor 的最大加強 score

    • 可以看到 ES 入門的加強 score 是2,在 max_boost 限制裡,所以不受影響

    • 而 ES 進階和 ES 最高難度的 field_value_factor 函數產生的加強 score 因為超過 max_boost 的限制,所以被設為 3

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match": {
                          "title": "ES"
                      }
                  },
                  "field_value_factor": {
                      "field": "like"
                  },
                  "max_boost": 3
              }
          }
      }
      
      "hits": [
          {
              "_score": 0.6092771, //原本是0.20309238
              "_source": { "title": "ES 進階", "like": 5 }
          },
          {
              "_score": 0.5753642, //原本是0.2876821
              "_source": { "title": "ES 入門", "like": 2 }
          },
          {
              "_score": 0.49621537, //原本是0.16540512
              "_source": { "title": "ES 最高難度", "like": 10 }
          }
      ]
      
  • 有時候線性的計算 new_score = old_score * like值 的效果並不是那麼好,field_value_factor 中還支持 modifier、factor 參數,可以改變 like 值對 old_score 的影響

    • modifier 參數支持的值

      • none : new_score = old_score * like值
        • 默認狀態就是 none,線性
      • log1p : new_score = old_score * log(1 + like值)
        • 最常用,可以讓 like 值字段的評分曲線更平滑
      • log2p : new_score = old_score * log(2 + like值)
      • ln : new_score = old_score * ln(like值)
      • ln1p : new_score = old_score * ln(1 + like值)
      • ln2p : new_score = old_score * ln(2 + like值)
      • square : 計算平方
      • sqrt : 計算平方根
      • reciprocal : 計算倒數
    • factor 參數

      • factor 作為一個調節用的參數,沒有 modifier 那麼強大會改變整個曲線,他僅改變一些常量值,設置 factor > 1 會提昇效果,factor < 1 會降低效果
      • 假設 modifier 是 log1p,那麼加入了 factor 的公式就是 new_score = old_score * log(1 + factor * like值)
    • 對剛剛的例子加上 modifier、factor

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match": {
                          "title": "ES"
                      }
                  },
                  "field_value_factor": {
                      "field": "like",
                      "modifier": "log1p",
                      "factor": 2
                  }
              }
          }
      }
      
  • 就算加上了 modifier,但是 “全文評分 與 field_value_factor 函數值乘積” 的效果可能還是太大,我們可以通過參數 boost_mode 來決定 old_score 和 加強 score 合併的方法

    • 如果將 boost_mode 改成 sum,可以大幅弱化最終效果,特別是使用一個較小的 factor 時

    • 加入了 boost_mode = sum、且 factor = 0.1 的公式變為 new_score = old_score + log(1 + 0.1 * like值)

    • GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match": {
                          "title": "ES"
                      }
                  },
                  "field_value_factor": {
                      "field": "like",
                      "modifier": "log1p",
                      "factor": 0.1
                  },
                  "boost_mode": "sum"
              }
          }
      }
      
  • 另外使用 field_value_factor 時要注意,有的文檔可能會缺少這個字段的值,因此這時就要加上 missing 來給這些缺失字段值的文檔一個 default 的值

    GET mytest/doc/_search
    {
        "query": {
            "function_score": {
                "query": {
                    "match": {
                        "title": "ES"
                    }
                },
                "field_value_factor": {
                    "field": "like",
                    "modifier": "log1p",
                    "factor": 0.1,
                    "missing": 1 //如果文檔沒有like值,就給他1的值讓他去做log1p的運算
                },
                "boost_mode": "sum"
            }
        }
    }