两路检索都返回分数,并不意味着它们可以直接加权。例如 L2
距离越小越相似,而内积通常越大越相似;即使方向相同,量级和分布也可能差得很远。
Milvus 的 WeightedRanker
用于融合多路检索结果。理解它时,要依次看候选集合、分数变换、权重与最终排序。
四个步骤
- 各路检索分别返回候选文档和分数。
- 将不同度量转换到可比较的相关性方向与范围。
- 为各路设置权重。
- 对相同文档的贡献求和,再按总分排序。
final_score(d) = Σᵢ wᵢ × normalized_scoreᵢ(d)
Milvus 文档说明了分数归一化与权重的约束:每个权重在 0 到 1
之间,权重数量应与检索请求数量一致。具体变换与度量类型和版本有关,不应把所有情况写成一个未经核对的通用变换。Milvus Reranking
权重之和不必固定为 1;把它们设为 0.6 和
0.4,主要是便于解释。若权重之和大于 1,最终融合分数也可能大于
1,它不是“相关概率”。
数值示例
假设图片与文本两路分数已经完成归一化,均为越大越相关。图片权重为
0.6,文本权重为 0.4;某一路未召回的文档,该路按 0 贡献计算。
| 文档 ID | 图片分数 | 文本分数 | 加权总分 |
|---|---|---|---|
| 101 | 0.92 | 0.87 | 0.900 |
| 203 | 0.88 | 未返回 | 0.528 |
| 150 | 0.85 | 未返回 | 0.510 |
| 198 | 0.83 | 0.91 | 0.862 |
| 175 | 0.80 | 0.82 | 0.808 |
| 110 | 未返回 | 0.85 | 0.340 |
| 250 | 未返回 | 0.78 | 0.312 |
例如,文档 198 的分数是
0.83×0.6 + 0.91×0.4 = 0.862。最终顺序为 101 > 198 >
175 > 203 > 150 > 110 > 250。
这个表演示的是归一化后的融合,不能把表里的数值当成原始 IP 或 L2
值再套用一次,期待得到相同结果。
在 Milvus 中表达权重
from pymilvus import WeightedRanker
ranker = WeightedRanker(0.6, 0.4)
这段代码只创建排序策略,不会自行检索。需要将它传给对应版本的混合检索接口,且权重顺序必须与两路搜索请求的顺序相同。
权重不是越精细越好
如果没有验证集,0.6/0.4 只是一个假设。实际调参可以比较单路检索、RRF
基线和几个简单的权重组合,观察 Recall@k、nDCG 或下游答案表现。
还要区分两类问题:相关文档已在候选中却排得靠后,可以研究融合;相关文档根本没有被任何一路返回,则需要改善召回和候选深度。
RRF 主要利用名次,WeightedRanker
主要利用变换后的分数。后者能够表达检索偏好,但也更依赖分数处理与权重设置是否合理。