Milvus 2.5 的 hybrid_search 里用 WeightedRanker 给 dense 0.8 与 sparse 0.2,结果几乎全是 dense 命中,型号类查询召回明显变差,BM25 那一路像没参与。
一开始怀疑是「两路请求的 limit 不一致,融合前就被截断」,查了一圈,方向不对。
这类报错背后常见的原因有几处,逐个排除就行。两路分数尺度不同,加权会被大分值主导。少数情况下是稀疏一路的 analyzer 没配,实际输出为空。
另外,权重写成了百分数,超过取值范围。
动手时先分别只跑 dense 与 sparse,看各自结果
python -c "from pymilvus import AnnSearchRequest;print(AnnSearchRequest(data=[q],anns_field='sparse',param={'metric_type':'BM25'},limit=20))"
再往下改用 RRFRanker 只依赖排名
python -c "from pymilvus import RRFRanker;print(RRFRanker(k=60))"
接着确认两路 limit 都设成 20 再融合
python -c "print({'dense':20,'sparse':20,'k':60})"
剩下的就是用型号类问题做一次对比评测
python eval_recall.py --mode hybrid --cases model_queries.json
当时还开着另一个排查窗口,两边日志对照着看才定位到。
恢复的判定其实很直接。型号查询的前 5 里出现正确文档,dense 与 sparse 各自也有命中,融合结果不再被单路主导。
这里还有个坑。加权融合要先做分数归一,图省事就用 RRF,只比排名不比分值,跨模型时更稳。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
