如何在OpenSearch/ElasticSearch中结合BM25与余弦相似度实现双评分查询
OpenSearch 双评分(BM25+余弦相似度)查询实现方案
需求实现思路
要先通过关键词筛选文档,再同时获取每个文档的BM25分数和向量余弦相似度分数,核心是保留原始BM25评分的同时,额外计算并返回余弦相似度分数。你之前用script_score会直接替换掉原始的BM25评分,所以无法同时拿到两个独立分数,改用以下两种方式即可实现:
方式一:仅筛选+返回双独立分数
这种方式先执行关键词筛选,再给每个返回文档附加BM25分数和余弦相似度分数,最终排序基于默认的BM25评分:
{ "size": 10, "query": { "query_string": { "query": "Redox AND Battery OR (Fuel Cell)", "default_field": "*" } }, "script_fields": { "bm25_score": { "script": { "source": "_score" } }, "cosine_similarity_score": { "script": { "source": "cosineSimilarity(params.query_value, doc[params.field])", "params": { "field": "vector", "query_value": [0.1, 0.2, 0.3, ...] // 替换为你的实际查询向量 } } } }, "_source": true // 可选,设为false则仅返回分数,不返回原始文档内容 }
- 外层
query是你的必填关键词筛选逻辑,OpenSearch会自动用BM25算法计算文档的原始评分_score script_fields用于额外计算并返回两个自定义字段:bm25_score直接读取默认的_score,即BM25的计算结果cosine_similarity_score通过脚本计算查询向量与文档向量的余弦相似度
方式二:筛选+双分数+自定义排序
如果需要基于BM25和余弦相似度的组合结果排序,同时保留两个独立分数,可用function_score实现:
{ "size": 10, "query": { "function_score": { "query": { "query_string": { "query": "Redox AND Battery OR (Fuel Cell)", "default_field": "*" } }, "functions": [ { "script_score": { "script": { "source": "cosineSimilarity(params.query_value, doc[params.field])", "params": { "field": "vector", "query_value": [0.1, 0.2, 0.3, ...] // 替换为你的实际查询向量 } } } } ], "score_mode": "sum", // 可选:multiply(相乘)、avg(平均)等,控制双分数的组合方式 "boost_mode": "sum" // 控制原始BM25分数与组合分数的结合方式 } }, "script_fields": { "original_bm25_score": { "script": { "source": "_score" } }, "cosine_similarity_score": { "script": { "source": "cosineSimilarity(params.query_value, doc[params.field])", "params": { "field": "vector", "query_value": [0.1, 0.2, 0.3, ...] // 替换为你的实际查询向量 } } } } }
function_score允许在原始BM25评分基础上,加入自定义评分函数(这里是余弦相似度)score_mode和boost_mode可按需调整,比如sum会将BM25分数和余弦相似度分数相加作为最终排序分- 同样通过
script_fields保留两个独立分数的返回
关键说明
script_score会完全覆盖原始的BM25评分,这是你之前无法同时获取两个分数的核心原因- 上述两种方式都能实现「布尔查询筛选→计算双独立分数」的流程,可根据是否需要自定义排序选择对应方案
内容的提问来源于stack exchange,提问作者Jake Winter
相关产品推荐
相关产品推荐

