Elasticsearch BM25 原理:为什么相关度排序靠谱
搜索"后端工程师",返回的结果凭什么排成这样?Elasticsearch 默认的 _score 排序用的是 BM25 算法。这篇文章把它讲透:三个因子、两个参数、以及和向量检索怎么配合。
一、BM25 是什么
BM25 是词频相关度算法的改进版,ES 5.0 起替代老的 TF-IDF 成为默认。核心思想:文档和查询越"相关",分越高。由三个因子组成:
二、三个因子逐个拆
因子 1:IDF(逆文档频率)——这个词有多稀有
直觉:
- “Elasticsearch"出现在 100 篇里 → 稀有 → IDF 高 → 匹配了很加分
- “的"出现在 90 万篇里 → 常见 → IDF 接近 0 → 匹配了不加分
这就是为什么搜索"简历 杭州"时,“杭州"比"简历"更能区分文档(简历到处都有,杭州更稀有)。
因子 2:TF 归一化(词频)——出现次数,但有上限
关键设计:词频有饱和:
- 出现 1 次 → 3 次:分涨得明显
- 出现 20 次 → 50 次:分几乎不涨
为什么:一篇文章提"Go"50 次不一定比提 10 次的相关性高 5 倍——可能只是废话多。饱和防止长文靠堆词刷分。
因子 3:长度归一化——短文更"值钱”
dl/avgdl:文档越长,TF 归一化衰减越多。
直觉:100 字的摘要里出现"Redis”,比 5000 字的论文里出现"Redis"更能说明主题相关——同样的词,在短文里的信息密度更高。
三、两个参数:k1 和 b
k1:词频饱和速度(默认 1.2)
- 调大(1.5-2.0):词频对分数影响更久(多出现更加分)→ 适合长文档主题判定
- 调小(0.5-1.0):出现几次就饱和 → 适合短文本、关键词精准匹配
b:长度归一化强度(默认 0.75)
- 调大(接近 1):长度惩罚更狠 → 短文优先
- 调小(接近 0):长度影响小 → 长文也能排前面
调参实战
|
|
调参前提:先建评测集(50-100 条标注好的"哪个结果该排前”),调参后跑评测对比——不评测的调参都是玄学。
四、BM25 的局限(为什么需要向量检索)
BM25 是词汇匹配:查询词和文档词必须字面重合。
这是 BM25 的天花板:理解不了语义。所以生产上:
BM25 管"字面对得上",向量管"意思靠得近"——两者是互补不是替代。这就是我在 RAG 工程化里混合检索的依据。
五、相关度调优的实战套路
总结
BM25 的核心认知:
- 三个因子:IDF 管稀有度、TF 管词频(有饱和)、长度归一化管信息密度
- 两个参数:k1 调饱和速度,b 调长度惩罚——先建评测再调参
- 天花板:词汇匹配,理解不了语义
- 出路:BM25 + 向量 + Rerank 三件套
相关度排序没有银弹,BM25 是那个"默认就挺靠谱"的基线——理解它,你才知道什么时候该调它,什么时候该加向量。