Elasticsearch 基础教程

Elasticsearch 高级教程

Elasticsearch 插件

Elasticsearch 笔记

Elasticsearch function_score 查询最强详解

Elasticsearch(es) 查询语句语法详解 Elasticsearch(es) 查询语句语法详解


Elasticsearch function_score 查询是可以自定义评分函数的方式进行打分,它允许为每个与主查询匹配的文档应用一个函数,以达到改变甚至完全替换原始查询评分 _score 的目的。

es 搜索结果默认会以文档的相关度进行排序,如果想要改变默认的排序规则,也可以通过 sort 参数指定一个或多个排序字段。但是使用 sort 排序过于绝对,适用规则化的层次排序,且它会直接忽略掉文档本身的相关度(根本不会去计算)。在很多时候这样做的效果并不好,这时候我们就需要对多个字段进行综合评估,具备一定泛化能力的评分排序,这时 function_score 就派上大用场了。

function_score 语句

示例

先上一个 function_score 语句示例:

{
  "from": 0,
  "size": 100,
  "query": {
    "function_score" : {
      "query" : {
        "bool" : {
          "must" : [
            {
              "multi_match" : {
                "query" : "三亚旅游",
                "fields" : [
                  "title^1.0",
                  "content^1.0"
                ],
                "type" : "best_fields",
                "operator" : "OR",
                "slop" : 0,
                "prefix_length" : 0,
                "max_expansions" : 50,
                "minimum_should_match" : "100%",
                "zero_terms_query" : "NONE",
                "auto_generate_synonyms_phrase_query" : true,
                "fuzzy_transpositions" : true,
                "boost" : 1.0       
              }
            },
          ],
          "filter" : [
            {
              "term" : {
                "status" : {
                  "value" : 1,
                  "boost" : 1.0
                }
              }
            }
          ],
          "adjust_pure_negative" : true,
          "boost" : 1.0
        }
      },
      "functions" : [
        {
          "filter" : {
            "match_all" : {
              "boost" : 1.0
            }
          },
          "script_score" : {
            "script" : {
              "source" : "double total = 0;total += 0.2764982*doc['ctr_7d'].value;total += 0.1296483*_score;total += -0.0796372*Math.log1p(doc['like_cnt_4_display'].value);total += 0.0296372*doc['like_rate'].value;total = total-3.10574001;return 1.0/(1.0+Math.exp(-total));",
              "lang" : "painless",
              "params" : {
                
              }
            }
          }
        }
      ],
      "boost_mode" : "multiply",
      "max_boost" : 3.4028235E38,
      "boost" : 1.0
    }
  },
  "_source": {
    "includes": ["id", "title", "content"],
    "excludes": []
  }
}

从上例中可以看出 function_score 语句主要分为两大块,一个是 query 子句,它负责匹配,另一个是 functions 子句,它起到对原有评分进行加强功能计算排序,其实就是重打分操作。

function_score 查询模板

function_score 查询模板可以分为两类,分别为单个加强函数的查询和多个加强函数的查询。

单个加强函数的查询模板:

{
  "query": {
    "function_score": {
      "query": {.....}, //  主查询,查询完后会有一个 _score 评分
      "field_value_factor": {...}, //  在 _score 的基础上进行强化评分
      "boost_mode": "multiply", //  指定用哪种方式结合 _score 和 强化 score
      "max_boost": 1.5 //  限制强化 score 的最高分,但是不会限制 _score
    }
  }
}

多个加强函数的查询模板:

{
  "query": {
    "function_score": {
      "query": {.....},
      "functions": [   //  可以有多个加强函数(或是 filter+加强函数),每一个加强函数会产生一个加强 score
        { "field_value_factor": ... },
        { "gauss": ... },
        { "filter": {...}, "weight": ... }
      ],
      "score_mode": "sum", //  决定加强 score 们如何整合
      "boost_mode": "multiply" //  决定最后的 functions 中 score 和 query score 的结合方式
    }
  }
}

function_score 参数

强化 _score 计算的函数

function_score 提供了几种内置加强 _score 计算的函数功能:

  • weight:设置一个简单而不被规范化的权重提升值。

    weight 加强函数和 boost 参数比较类似,可以用于任何查询,不过有一点差别是 weight 不会被 Lucene 规范化(normalize)成难以理解的浮点数,而是直接被应用。

    例如,当 weight 为 2 时,最终得分为 new_score = 2 * _score

  • field_value_factor:指定文档中某个字段的值结合 _score 改变分数;

    {
      "query": {
        "function_score": {
          "query": {.....},
          "field_value_factor": {
            "field": "view_cnt",
            "modifier": "none",
            "factor": 1.2
          },
          "boost_mode": "multiply",
          "max_boost": 1.5
        }
      }
    }

    调整后的 function 分数公式为,factor * doc['view_cnt'].value

    此外,针对指定字段的缺失情况,提供了缺省值的设置,以及数据计算方式,如下:

    {
      "query": {
        "function_score": {
          "query": {.....},
          "field_value_factor": {
            "field": "view_cnt",
            "modifier": "ln1p",
            "missing": 1.0,
            "factor": 1.2
          },
          "boost_mode": "multiply",
          "max_boost": 1.5
        }
      }
    }

    function 分数为,ln1p(1.2 * doc['view_cnt'].value),如果指定字段缺失用 missing 对应的值,至于和匹配的相关性分数 _score 如何结合需要下面的 boost_mode 参数来决定。

  • random_score:使用一致性随机分值计算来对每个用户采用不同的结果排序方式,对相同用户仍然使用相同的排序方式,其本质上用的是 seed 种子参数,用户相关的 id 与 seed 构造映射关系,就可千人千面的效果,seed 不同排序结果也不同。具体示例如下:

    {
      "query": {
        "function_score": {
          "query": {.....},
          "random_score": {
            "seed": 10,
            "field": "_seq_no"
          }
        }
      }
    }
  • 衰减函数(decay function):es 内置了三种衰减函数,分别是 linearexpgauss;三种衰减函数的差别只在于衰减曲线的形状,在 DSL 的语法上的用法完全一样;linear 是线性函数,它是一条直线,exp 是指数函数,它先剧烈衰减然后变缓,最后一个是最常用的 guass,高斯函数是钟形的,它的衰减速率是先缓慢,然后变快,最后又放缓。

    实际使用中,衰减函数以某个字段的值为基准,距离某个值越近得分越高。

  • script_score:当需求超出以上范围时,可以用自定义脚本完全控制评分计算。

其它辅助函数

boost_mode 参数决定 query 中的相关性分数和加强的函数分数的结合方式。

  • multiply:默认的配置,两者分数相乘,new_score = _score * boost_score
  • sum:两者相加,new_score = _score + boost_score
  • min:取两者最小值,new_score = min(_score, boost_score)
  • max:取两者最大值,new_score = max(_score, boost_score)
  • replace:用 boost_score 替换 _score 值。

score_mode 参数决定 functions 里面的强化 score 如何结合,function_score 先会执行 score_mode 的设置,即先整合所有的强化计算,再执行 boost_mode 的配置,就是将 query 相关性分数和整合强化分数的结合

  • multiply:默认的配置,多个强化分数相乘;
  • sum:多个强化分数相加;
  • min:取多个强化分数最小值;
  • max:取多个强化分数最大值;
  • avg:取多个强化分数平均值;
  • first:使用首个函数的结果作为最终结果。

max_boost:限制加强函数的最大效果,就是限制加强 score 最大能多少,但要注意不会限制 old_score

  • 如果加强 score 超过了 max_boost 限制的值,会把加强 score 的值设成 max_boost 的值;
  • 假设加强 score 是5,而 max_boost 是2,因为加强 score 超出了 max_boost 的限制,所以 max_boost 就会把加强 score 改为2。简单的说,就是 final_score = min(整合后的 score, max_boost)。