ES 0.90.4 新增 function_score,用来统一收掉 0.90 早期三个独立打分查询:custom_boost_factor、custom_score、custom_filters_score,三者在同版标记废弃;function_score 用一层 DSL,通过 functions[]、score_mode、boost_mode 控制,把 “按条件加权、脚本算分、多过滤器分支打分” 三类能力收拢成同一个查询结构。很多人容易搞混两个维度:score_mode 是多个 function 之间怎么合并,boost_mode 是 function 合并结果和主查询原始_score 怎么结合。下面从旧三个查询对照、结构、参数、示例、坑点拆开。
一、原来三个打分查询分别对应什么
| 旧查询 | 作用 | function_score 里等价写法 |
|---|---|---|
| custom_boost_factor | 匹配就给固定倍数乘分 | filter + weight |
| custom_score | 脚本自定义计算分数 | filter + script_score |
| custom_filters_score | 多组 filter,命中哪一组就取对应权重 | 多条 filter-function,配合 score_mode |
核心背景:0.90 早期这三个是互相独立的查询类型,不能直接嵌套组合;function_score 出来之后,全部改成放在 functions 数组里的多条带 filter 的函数,一条 function 对应原来一个分支打分逻辑。
二、function_score 两层合并规则(重点)
- score_mode:控制 functions 内部多个函数结果怎么合并
- multiply(默认):函数结果相乘
- sum:全部相加(最接近多 filter 累加 boost 场景)
- avg:平均
- max:取命中函数里最大分
- min:取最小
- first:拿第一个命中 filter 的函数结果(等价老 custom_filters_score 的 “命中优先”)
- boost_mode:函数合并结果 和 主 query 原始_score 怎么结合
- multiply(默认):_score * func_result
- sum:_score + func_result
- replace:直接用 func_result 覆盖原始_score(迁移老 custom_score 最容易踩坑:老 custom_score 默认是 replace,不写 replace 就会多乘一次原始分)
- max / min
老 custom_score 的原生行为:脚本输出直接作为文档总分,对应 boost_mode: "replace";不写 replace,就变成 原始分 × 脚本分,分数直接飘了。
三、标准结构示例(3 个打分分支收进同一个 function_score)
假设三个分支:
- 满足 filterA:weight=2
- 满足 filterB:脚本算分
- 满足 filterC:weight=1.5
主查询是基础 match,三个分支并行打分,函数结果相加,再乘原始相关性分:
{
"query": {
"function_score": {
"query": { "match": { "title": "java" } },
"functions": [
{ "filter": { "term": { "tag": "hot" } }, "weight": 2 },
{ "filter": { "range": { "pv": { "gte": 1000 } } }, "script_score": { "script": "doc['pv'].value / 1000" } },
{ "filter": { "term": { "tag": "new" } }, "weight": 1.5 }
],
"score_mode": "sum",
"boost_mode": "multiply"
}
}
}
如果要复刻老 custom_filters_score“按顺序优先匹配、只取第一个命中分支”,改成 score_mode:"first"。
复刻老 custom_score 单脚本打分:只保留一条 script_score 函数,boost_mode:"replace"。
四、迁移路线(三分查询 → function_score)
- 多个 custom_boost_factor → 多条 filter+weight,score_mode 选 sum/multiply
- custom_score(脚本)→ script_score 函数,务必核对 boost_mode 是否要 replace
- custom_filters_score(多 filter 有序分支)→ 多条 filter-function,score_mode: first
- 混合三种逻辑:全部塞进同一个 functions 数组,用 score_mode 统一合并分支结果,boost_mode 控制和基础分的关系
五、0.90 版本专属坑(和新版 ES 不一样)
- 0.90.5 改了一次参数命名,早期文档里 mode 和现在 score_mode 名字有变动,优先以 0.90.4 + 标准 score_mode 为准
- 老 custom_score 默认是 replace 行为,很多迁移漏写 replace,分数翻倍、失真
- filter 不命中的 function 返回 1,不是 0;如果 score_mode 是 multiply,不命中的分支不会改变乘积
- 0.90 的 function_score 不支持 decay 函数(decay 是后面版本才补齐),只有 weight、script_score 两类函数
六、避坑清单
- 区分:score_mode 是函数之间合并,boost_mode 是函数合并结果 vs 主查询分,不要搞混
- 想和老 custom_score 行为对齐,一定要显式 boost_mode:"replace"
- 老 custom_filters_score 是顺序优先,不是叠加,迁移必须 score_mode:"first",不是 sum
- 0.90.0~0.90.3 没有 function_score,只能用那三个旧查询;0.90.4 才可以统一收拢
- 脚本里不要把原始_score 再乘一遍,boost_mode 已经负责组合逻辑
【相关 FAQ】
问题 1:ES 0.90 原来三个打分查询,function_score 是怎么把它们收成一个的?
回答 1:function_score 用 functions 数组,把 custom_boost_factor 映射成 filter+weight、custom_score 映射成 script_score、custom_filters_score 映射成多条带 filter 的函数;通过 score_mode 合并多个函数输出,boost_mode 控制和主查询原始_score 的结合方式,全部收拢在同一个 function_score 查询里。
问题 2:score_mode 和 boost_mode 区别是什么,迁移老 custom_score 要注意什么?
回答 2:score_mode 控制 functions 里多个打分分支之间怎么合并;boost_mode 控制合并后的函数分和主查询相关性分怎么运算;老 custom_score 默认直接替换原始分,迁移时必须加 boost_mode:"replace",否则会变成原始分 × 脚本分,结果不对。
问题 3:如果我要复刻旧 custom_filters_score,命中哪个 filter 就只用那一条的分数,score_mode 怎么设?
回答 3:设置 score_mode:"first",function_score 会按数组顺序,取第一个命中 filter 的函数结果,其余分支忽略,和老 custom_filters_score 优先匹配逻辑一致。
问题 4:0.90 早期版本都能用 function_score 吗?
回答 4:不能,0.90.0~0.90.3 没有 function_score,只能用 custom_boost_factor/custom_score/custom_filters_score;0.90.4 才新增 function_score,同时标记这三个旧查询废弃。
【参考资料】
[2026-10-26](腾讯云开发者社区 ES0.90 function_score 三分查询迁移)腾讯云开发者社区
[ES 官方 0.90.4 release notes function_score 新增、旧查询废弃] Elastic archive
[Elastic old guide custom_filters_score /custom_score] Elastic 旧权威指南
[Elastic old guide function_score score_mode boost_mode] Elastic 文档存档
【免责声明】
本文基于 Elasticsearch 0.90.4 版本特性;0.90 属于极早期版本,参数、脚本语法、行为和 ES1.x 之后差异很大,不建议直接套新版 ES;迁移前务必在同版本做对照回归,核对分数对齐。
