在信息检索(IR)、推荐系统和多模态检索中,我们常常需要融合来自多个检索器或模型的结果。不同检索器可能对同一文档打出的分数差异很大,如果直接简单加权,很容易出现某个检索器“主导融合结果”的情况。
Distribution-Based Score Fusion (DBSF) 是一种基于分布的分数融合方法,它通过统计方法对各检索器的分数进行归一化和标准化,使得融合过程更加稳健和公平。
背景
在多检索器融合中,我们通常面临以下问题:
-
分数尺度不统一
-
BM25 输出的分数范围可能是 0–30
-
Dense Embedding 输出余弦相似度,范围可能是 0–1
-
-
分布形态差异大
-
某些检索器的分数分布可能非常集中(方差小)
-
某些检索器存在极端值(outliers)
-
-
传统方法的局限
-
Min-Max 或 Z-score 归一化 + 加权融合
-
容易受 outlier 影响
-
对分布差异大的检索器不够稳健
-
-
人工加权需要经验和先验知识
-
DBSF 应运而生,它通过统计分布的方式统一各检索器的贡献,不依赖复杂的手动权重。
DBSF 的原理
DBSF 的核心步骤如下:
-
计算均值和标准差
对每个检索器的分数集计算:-
均值 μ
-
标准差 σ
-
-
截断分数到 μ±3σ
-
小于 μ−3σ 的分数 → 0
-
大于 μ+3σ 的分数 → 1
-
中间分数线性缩放到 0–1
-
-
标准化与归一化
对在 μ±3σ 区间的分数: -
融合分数
将各检索器的归一化分数相加(或平均):
这种方法能够避免极端值影响,同时保证不同检索器的信号都有贡献。
优缺点
优点
-
稳健性高:对 outlier 不敏感
-
分布自适应:不同检索器的分数分布差异大时效果更好
-
无需手动调权重:自动平衡各检索器的贡献
-
易于实现:基于均值和标准差即可
缺点
-
无法体现先验偏好:如果某个检索器非常重要,DBSF 不会自动偏向它
-
假设分数近似正态分布:在极端非正态分布下,μ±3σ 截断可能不完全合理
-
单纯线性加权:融合逻辑简单,可能无法捕捉复杂关系
示例代码(Python)
下面是一个简化实现示例:
import numpy as np
from collections import defaultdictdef normalize_dbsf(scores):values = np.array(list(scores.values()))mu, sigma = values.mean(), values.std(ddof=1) if len(values) > 1 else (values.mean(), 1e-9)lower, upper = mu - 3*sigma, mu + 3*sigmanorm_scores = {}for doc, s in scores.items():if upper == lower:ns = 0.5else:ns = (s - lower) / (upper - lower)ns = max(0.0, min(1.0, ns))norm_scores[doc] = nsreturn norm_scoresdef dbsf_fusion(results_list):fused = defaultdict(float)for scores in results_list:norm_scores = normalize_dbsf(scores)for doc, ns in norm_scores.items():fused[doc] += nsreturn sorted(fused.items(), key=lambda x: x[1], reverse=True)# 示例数据
bm25 = {"doc1": 28.4, "doc2": 17.2, "doc3": 3.9, "doc4": 10.5}
dense = {"doc1": 0.78, "doc2": 0.65, "doc3": 0.52, "doc4": 0.31}
ctr = {"doc1": 0.045, "doc2": 0.032, "doc3": 0.028, "doc4": 0.041}# 融合
fused_results = dbsf_fusion([bm25, dense, ctr])
print(fused_results)
输出示例:
[('doc1', 2.07), ('doc2', 1.53), ('doc4', 1.25), ('doc3', 1.15)]
可以看到,doc3
虽然在 BM25 分数很低,但在 Dense 和 CTR 中仍然贡献了一部分分数,被合理保留在排名中。
llama_index 相关的代码实现。
from llama_index.core.retrievers import QueryFusionRetrieverretriever = QueryFusionRetriever([vector_retriever, bm25_retriever],retriever_weights=[0.6, 0.4],similarity_top_k=10,num_queries=1, # set this to 1 to disable query generationmode="dist_based_score",use_async=True,verbose=True,
)nodes_with_scores = retriever.retrieve("What happened at Interleafe and Viaweb?"
)for node in nodes_with_scores:print(f"Score: {node.score:.2f} - {node.text[:100]}...\n-----")
应用场景示例
-
多检索器文本搜索:BM25 + Dense Embedding + Click-Through Rate
-
多模态检索:文本检索 + 图像相似度
-
跨语言检索:原文语言 + 翻译语言
-
推荐系统:不同算法输出的评分融合
DBSF 在这些场景下都能显著提升融合结果的稳健性和多样性。
总结
-
DBSF 是一种基于统计分布的分数融合方法
-
通过 μ±3σ 截断 + 标准化 + 相加,实现多检索器结果的稳健融合
-
适合 分布差异大、没有明确权重先验 的场景
-
实现简单,可用 Python 自定义,也可以使用如 LlamaIndex、Qdrant、Upstash 等系统内置功能
📚 参考资料
-
LlamaIndex 文档:Relative Score Fusion 和 Distance-Based Score Fusion
-
Qdrant 文档:Hybrid Queries
-
Upstash 文档:Hybrid Indexes