目录一、索引创建与查询二、使用 script_score 的查询boost_mode: replace参数说明公式解释三、使用 script_score 的查询boost_mode: sum boost: 2.0参数说明公式解释四、预期返回结果对比五、进阶动态权重与参数传递适用于两种模式5.1 replace 模式动态权重5.2 sum 模式动态权重配合 boost 参数六、注意事项一、索引创建与查询# 创建索引curl-s-u$AUTH-XPUT$ES/user-HContent-Type: application/json-d { settings: { number_of_shards: 1, number_of_replicas: 0, analysis: { analyzer: { nickname_analyzer: { type: custom, tokenizer: standard, filter: [lowercase] } } } }, mappings: { properties: { uid: { type: keyword }, nickname: { type: text, analyzer: nickname_analyzer, fields: { keyword: { type: keyword } } }, fans_count: { type: long }, wealth_level: { type: integer }, live_level: { type: integer } } } } |jq.# 插入测试数据curl-s-u$AUTH-XPOST$ES/user/_doc-HContent-Type: application/json-d {uid: 1001, nickname: Zhang Sanfeng, fans_count: 1500000, wealth_level: 80, live_level: 75} |jq.curl-s-u$AUTH-XPOST$ES/user/_doc-HContent-Type: application/json-d {uid: 1002, nickname: Zhang Wuji, fans_count: 980000, wealth_level: 92, live_level: 88} |jq.curl-s-u$AUTH-XPOST$ES/user/_doc-HContent-Type: application/json-d {uid: 1003, nickname: Linghu Chong, fans_count: 320000, wealth_level: 65, live_level: 70} |jq.二、使用script_score的查询boost_mode: replacecurl-s-u$AUTH$ES/user/_search-HContent-Type: application/json-d { size: 10, query: { function_score: { query: { match: { nickname: Zhang } }, script_score: { script: { lang: painless, source: // 原始匹配得分由 match 查询计算 double matchScore _score; // 粉丝数使用对数平滑log(1 fans_count) double fans Math.log(1 doc[fans_count].value); // 财富等级和直播等级直接使用原值范围 1-100 double wealth doc[wealth_level].value; double live doc[live_level].value; // 加权求和匹配度权重2.0粉丝数权重1.0财富等级权重1.5直播等级权重1.2 double finalScore matchScore * 2.0 fans * 1.0 wealth * 1.5 live * 1.2; return finalScore; } }, boost_mode: replace // 用脚本得分替换原始 _score } } } |jq.参数说明参数值作用script_score.script.sourcePainless 脚本自定义得分计算公式boost_modereplace用脚本计算的得分覆盖原始_score不累加。_score在脚本中自动传入代表原始查询match计算出的相关性得分公式解释最终得分 matchScore × 2.0匹配度权重 log(1 fans_count) × 1.0粉丝数对数平滑 wealth_level × 1.5财富等级线性 live_level × 1.2直播等级线性三、使用script_score的查询boost_mode: sumboost: 2.0该模式通过boost参数将原始匹配得分乘以系数 2然后与脚本计算的自定义得分相加达到与replace模式完全相同的结果。脚本中只负责业务字段的计算不包含_score。curl-s-u$AUTH$ES/user/_search-HContent-Type: application/json-d { size: 10, query: { function_score: { query: { match: { nickname: Zhang } }, boost: 2.0, // 原始 _score 乘以 2 script_score: { script: { lang: painless, source: // 粉丝数使用对数平滑log(1 fans_count) double fans Math.log(1 doc[fans_count].value); // 财富等级和直播等级直接使用原值 double wealth doc[wealth_level].value; double live doc[live_level].value; // 返回脚本部分得分不包含匹配度 return fans * 1.0 wealth * 1.5 live * 1.2; } }, boost_mode: sum // 最终得分 boost * _score 脚本得分 } } } |jq.参数说明参数值作用boost2.0原始_score乘以该系数script_score.script.source脚本不含matchScore项仅计算粉丝数、财富等级、直播等级的加权和boost_modesum最终得分 boost × _score 脚本返回值公式解释最终得分 _score × 2.0匹配度权重由boost参数实现 log(1 fans_count) × 1.0 wealth_level × 1.5 live_level × 1.2注意boost_mode: sum会将boost × _score与脚本返回值相加。如果未显式设置boost则默认为 1.0。四、预期返回结果对比两种模式现在采用相同的权重系数因此最终得分完全一致。假设匹配度如下示例数值用户原始_score(match)fans_countlog(1fans)wealthlive脚本得分最终得分Zhang Wuji0.5980000≈13.8928813.8138105.6 257.40.5×2 257.4 258.4Zhang Sanfeng0.61500000≈14.2807514.212090 224.20.6×2 224.2 225.4返回 JSON 结构两种模式结果相同{hits:{total:{value:2,relation:eq},max_score:258.4,hits:[{_score:258.4,_source:{uid:1002,nickname:Zhang Wuji,fans_count:980000,wealth_level:92,live_level:88}},{_score:225.4,_source:{uid:1001,nickname:Zhang Sanfeng,fans_count:1500000,wealth_level:80,live_level:75}}]}}五、进阶动态权重与参数传递适用于两种模式通过params将权重作为参数传递便于动态调整无需修改脚本。5.1replace模式动态权重curl-s-u$AUTH$ES/user/_search-HContent-Type: application/json-d { size: 10, query: { function_score: { query: { match: { nickname: Zhang } }, script_score: { script: { lang: painless, source: double matchScore _score; double fans Math.log(1 doc[fans_count].value); double wealth doc[wealth_level].value; double live doc[live_level].value; return matchScore * params.matchWeight fans * params.fansWeight wealth * params.wealthWeight live * params.liveWeight; , params: { matchWeight: 2.0, fansWeight: 1.0, wealthWeight: 1.5, liveWeight: 1.2 } } }, boost_mode: replace } } } |jq.5.2sum模式动态权重配合boost参数curl-s-u$AUTH$ES/user/_search-HContent-Type: application/json-d { size: 10, query: { function_score: { query: { match: { nickname: Zhang } }, boost: 2.0, script_score: { script: { lang: painless, source: double fans Math.log(1 doc[fans_count].value); double wealth doc[wealth_level].value; double live doc[live_level].value; return fans * params.fansWeight wealth * params.wealthWeight live * params.liveWeight; , params: { fansWeight: 1.0, wealthWeight: 1.5, liveWeight: 1.2 } } }, boost_mode: sum } } } |jq.六、注意事项性能script_score会为每个匹配文档执行脚本如果结果集很大例如数万性能会显著下降。建议优先使用field_value_factor组合只有公式复杂时再用脚本。数值范围归一化粉丝数使用log(1 value)是常见平滑方法如果希望线性归一化到 [0,1]可以结合params.maxFans进行缩放。缺失值处理如果某些文档的字段可能缺失脚本中需使用doc[field].size() ! 0 ? doc[field].value : defaultValue避免报错。脚本编译Elasticsearch 会缓存编译后的脚本但频繁修改脚本内容会消耗资源。sum模式与boost的配合通过设置boost可以灵活调整原始匹配度的权重而无需修改脚本。这是推荐的做法逻辑更清晰维护成本更低。两种模式等价性当boost_mode: replace脚本中包含_score * W且boost_mode: sum设置boost: W且脚本中不含_score时两者完全等价。可根据个人偏好选择。以上完整示例展示了两种实现相同加权排序的方法可直接在你的集群中运行测试。