ElasticSearch - function_score(weight 具體實例)

古古

2018/07/06


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

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

    { "language": "java", "like": 5 }
    { "language": "python", "like": 5 }
    { "language": "go", "like": 10 }
    
  • functions 是一個數組,裡面放著的是將要被使用的加強函數列表,我們在裡面使用了 3 個 filter 去過濾數據,並且每個 filter 都設置了一個加強函數,並且還使用了一個會應用到所有文檔的 field_value_factor 加強函數

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

    • 一個文檔可以一次滿足多條加強函數和多個 filter,如果一次滿足多個,那麼就會產生多個加強 score

    • 因此 ES 會先使用 score_mode 定義的方式來合併這些加強 score 們,得到一個總加強 score,得到總加強 score之後,才會再使用 boost_mode 定義的方式去和 old_score 做合併

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match_all": {}  //match_all查出來的所有文檔的_score都是1
                  },
                  "functions": [
                      //第一個filter(使用weight加強函數),如果language是java,加強score就是2
                      {
                          "filter": {
                              "term": {
                                  "language": "java"
                              }
                          },
                          "weight": 2
                      },
                      //第二個filter(使用weight加強函數),如果language是go,加強score就是3
                      {
                          "filter": {
                              "term": {
                                  "language": "go"
                              }
                          },
                          "weight": 3
                      },
                      //第三個filter(使用weight加強函數),如果like數大於等於10,加強score就是5
                      {
                          "filter": {
                          	"range": {
                              	"like": {
                                  	"gte": 10
                                  }
                              }
                          },
                          "weight": 5
                      },
                      //field_value_factor加強函數,會應用到所有文檔上,加強score就是like值
                      {
                          "field_value_factor": {
                          	"field": "like"
                          }
                      }
                  ],
                  "score_mode": "multiply", //設置functions裡面的加強score們怎麼合併成一個總加強score
                  "boost_mode": "multiply" //設置old_score怎麼和總加強score合併
              }
          }
      }
      
      "hits": [
          {
              //go同時滿足filter2、filter3
              //且還有一個加強函數field_value_factor產生的加強
              //因此加強score為3, 5, 10,總加強score為3*5*10=150
              "_score": 150,
              "_source": { "language": "go", "like": 10 }
          },
          {
              //java只滿足filter1
              //但是因為還有field_value_facotr產生的加強score
              //因此加強score為2, 5,總加強score為2*5=10
              "_score": 10,
              "_source": { "language": "java", "like": 5 }
          },
          {
              //python不滿足任何filter
              //因此加強score只有field_value_factor的like值
              //就是5
              "_score": 5,
              "_source": { "language": "python", "like": 5 }
          }
      ]
      
  • 其實 weight 加強函數也是可以不和 filter 搭配,自己單獨使用的,只是這樣做沒啥意義,因為只是會給全部的文檔都增加一個固定值而已

    • 不過就 DSL 語法上來說,他也像其他加強函數一樣,是可以直接使用而不用加 filter 的

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match_all": {}
                  }
              },
              functions: [
                  {
                      "weight": 3
                  }
              ]
          }
      }
      
      "hits": [
          {
              "_score": 3,
              "_source": { "language": "go", "like": 10 }
          },
          {
              "_score": 3,
              "_source": { "language": "python", "like": 5 }
          },
          {
              "_score": 3,
              "_source": { "language": "java", "like": 5 }
          }
      ]
      
  • weight 加強函數也可以用來調整每個語句的貢獻度,權重 weight 的默認值是 1.0,當設置了 weight,這個 weight 值會先和自己那個 {} 裡的每個句子的評分相乘,之後再通過 score_mode 和其他加強函數合併

    • 下面的查詢,公式為 new_score = old_score * [ (like值 * weight1) + weight2 ]

    • 公式解析 : weight1 先加強 like 值(只能使用乘法),接著再透過 score_mode 定義的方法(sum)和另一個加強函數 weight2 合併,得到一個總加強 score,最後再使用 boost_mode 定義的方法(默認是 multiply)和 old_score 做合併,得到 new_score

      GET mytest/doc/_search
      {
          "query": {
              "function_score": {
                  "query": {
                      "match_all": {}
                  }
              },
              functions: [
                  {
                      "field_value_factor": {
                      	"field": "like"
                      },
                      "weight": 3  //weight1, 加強field_value_factor,只能使用乘法,無法改變
                  },
                  {
                      "weight": 20 //weight2
                  }
              ],
              "score_mode": "sum"
          }
      }
      
      "hits": [
          {
              "_score": 50,
              "_source": { "language": "go", "like": 10 }
          },
          {
              "_score": 35,
              "_source": { "language": "python", "like": 5 }
          },
          {
              "_score": 35,
              "_source": { "language": "java", "like": 5 }
          }
      ]