场景

在使用 match 查询时,Elasticsearch 会根据文档与搜索词条的关联度计算得分(_score),并按得分降序返回结果。如果需要人为控制文档的相关性算分,可以使用 Elasticsearch 的 function_score 查询。

用法

基本语法

function_score 查询中包含四部分内容:

  • 原始查询条件:query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分(query score)
  • 过滤条件:filter部分,符合该条件的文档才会重新算分
  • 算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分(function score),有四种函数
    • weight:函数结果是常量
    • field_value_factor:以文档中的某个字段值作为函数结果
    • random_score:以随机数作为函数结果
    • script_score:自定义算分函数算法
  • 运算模式:算分函数的结果、原始查询的相关性算分,两者之间的运算方式,包括:
    • multiply:相乘
    • replace:用function score替换query score
    • 其它,例如:sum、avg、max、min
运行流程
  1. 根据原始条件查询搜索文档,并且计算相关性算分,称为原始算分(query score)
  2. 根据过滤条件,过滤文档
  3. 符合过滤条件的文档,基于算分函数运算,得到函数算分(function score)
  4. 原始算分(query score)和函数算分(function score)基于运算模式做运算,得到最终结果,作为相关性算分。

因此,其中的关键点是:

  • 过滤条件:决定哪些文档的算分被修改
  • 算分函数:决定函数算分的算法
  • 运算模式:决定最终算分结果

案例

商城中商品有一个广告字段isAD,搜索时被推广的商品将排在最前。

实现以上需求,需要指定query类型为function_score,并在原始query的基础上,增加一个算分函数,人为过滤出包含推广字段的文档,并将得分附加上一个足够大的权重,查询语句如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"query": {
"function_score": {
"query": {
"match": {
"name": "手机"
}
},
"functions": [
{
"filter": {
"term": {
"isAD": true
}
},
"weight": 1000
}
],
"boost_mode": "sum"
}
}
}

对应到java代码如下:

1
2
3
4
5
6
7
FilterFunctionBuilder[] functions = {
new FilterFunctionBuilder(QueryBuilders.termQuery("isAD", true), // 1.
ScoreFunctionBuilders.weightFactorFunction(1000)) // 2.
};
request.source().query(QueryBuilders
.functionScoreQuery(bool, functions) // 3.
.boostMode(CombineFunction.SUM)); // 4.
代码注释说明
  1. 过滤条件:指定被推广的文档(isAD: true)。
  2. 算分函数:为符合条件的文档赋予权重 1000。
  3. 原始查询:基于商品名称 name 匹配 “手机”。
  4. 运算模式:将原始分数与函数值相加。
注意事项
  • 只有在使用 match 查询时,才会根据得分排序,function_score 才会生效。
  • 如果需要对所有文档应用算分函数,可以省略 filter 部分。
  • 确保字段名称(如 isAD)和查询条件(如 term 查询)与实际索引中的字段一致。

__END__