上篇我们理解了 TF-IDF 的基本逻辑。BM25 是它的改进版,修掉了两个明显缺陷。本文从公式结构到实际计算,逐步拆解每一个细节,无需数学基础也能读懂。
一、TF-IDF 的两个缺陷
回顾上篇的结论:TF-IDF 用"词频 × 逆文档频率"来衡量一个词的重要性。但它有两个问题:
缺陷一:词频线性增长 一个词出现 10 次,得分是出现 5 次的整整两倍。但现实中,同一个词反复出现,边际价值是递减的------从 0 次到 1 次是质变,从 9 次到 10 次几乎没什么意义。
缺陷二:没有校正文档长度 同一个词在一篇 500 字的短文里出现 3 次,和在一篇 5 万字的长文里出现 3 次,重要性截然不同。短文里它更"密集",更能代表主题。TF-IDF 对此视而不见。
BM25 就是针对这两点的经典修正。
二、BM25 公式全貌
Score(Q,D)=∑iIDFBM25(qi)⋅TF(qi,D)+k1(1−b+b⋅avgdl∣D∣)TF(qi,D)(k1+1)
看起来很长,但拆开来只有三个独立模块,加上一个求和符号。
三、模块一:∑ 求和符号
∑i
查询 Q 通常包含多个词,比如"模型蒸馏"会被拆成"模型"和"蒸馏"两个词。
对每个词 qi 分别算一个得分,最后加总,就是这篇文档对这条查询的总得分。多个词同时命中,得分会叠加------这也是为什么"同时包含两个关键词的文档"往往排名更高。
四、模块二:IDF 部分(稀有词加权)
BM25 对 IDF 的写法和 TF-IDF 略有不同:
IDFBM25(t)=lnDF(t)+0.5N−DF(t)+0.5
- N = 语料库文档总数
- DF(t) = 包含词 t 的文档数
和 TF-IDF 相比,分子从"N(总数)"换成了"N − DF(t)(不含该词的文档数)":
| TF-IDF | BM25 | |
|---|---|---|
| 分子含义 | 文档总数 | 不含该词的文档数 |
| 传达的意思 | 总共有多少文档 | 不含它的文档是含它的多少倍 |
分子分母各加 0.5,是为了防止极端情况(比如某个词出现在所有文档里,DF = N,分子变成 0.5,公式不会崩掉)。
代入例子感受一下,假设语料库共 10 篇文档:
"模型"出现在 3 篇(df = 3):
IDF=ln3+0.510−3+0.5=ln3.57.5=ln(2.14)≈0.76
"蒸馏"出现在 2 篇(df = 2):
IDF=ln2+0.510−2+0.5=ln2.58.5=ln(3.4)≈1.22
"蒸馏"更稀有,IDF 更高,符合直觉。
五、模块三:TF 饱和(BM25 最核心的改进)
TF+k1TF×(k1+1)
(先忽略长度部分,只看 k1 的作用)
当 TF 非常大时,这个分数会趋近于 (k1+1),不会无限增长------这就是饱和。
用数字感受一下( k1=1.5):
| 出现次数(TF) | 得分 | 增量 |
|---|---|---|
| 1 | 1.00 | --- |
| 2 | 1.40 | +0.40 |
| 5 | 2.00 | +0.60 |
| 10 | 2.20 | +0.20 |
| 100 | 2.49 | 几乎不动 |
出现 10 次不会是出现 5 次的两倍,边际贡献越来越小------这才符合现实。
k1 的值控制饱和的速度, k1 越小,越早到达上限; k1 越大,增长空间越大。
六、模块四:长度归一化(分母里的 b)
分母里这一段负责惩罚长文档:
k1(1−b+b⋅avgdl∣D∣)
- ∣D∣ = 当前文档长度(词数)
- avgdl = 语料库平均文档长度
- b∈0,1,控制归一化强度
直觉:文档比平均值长 , ∣D∣/avgdl>1,分母变大,得分被压低;文档比平均值短,分母变小,得分略微提升。
| b 的值 | 效果 |
|---|---|
| b = 0 | 完全不考虑文档长度 |
| b = 1 | 完全按长度归一化 |
| b = 0.75 | 实践中最常用的默认值 |
以 doc_1(文档长度 200 词,avgdl = 250)为例:
1.5×(1−0.75+0.75×250200)=1.5×(0.25+0.6)=1.5×0.85=1.275
doc_1 比平均文档短,惩罚项(1.275)小于 k1(1.5),因此短文档得到了轻微奖励。
七、手算一遍:验证日志里的数字
以下是一段真实的 BM25 运行日志,我们来手算验证它:
ini
查询分词: ["模型", "蒸馏"]
词 "模型" → df=3, IDF=0.76
doc_1: TF=5, 文档长度=200词, BM25贡献=1.52
词 "蒸馏" → df=2, IDF=1.22
doc_1: TF=3, 文档长度=200词, BM25贡献=2.15
最终排序: doc_1 (3.67) > doc_7 (1.68) > doc_5 (1.22) > doc_3 (0.82)
参数: k1=1.5, b=0.75, avgdl=250
第一步:算 doc_1 的长度惩罚项
k1(1−b+b⋅avgdl∣D∣)=1.5×(0.25+0.75×250200)=1.5×0.85=1.275
第二步:算"模型"在 doc_1 的贡献(IDF = 0.76,TF = 5)
0.76×5+1.2755×(1.5+1)=0.76×6.27512.5=0.76×1.99≈1.51
日志显示 1.52,误差来自中间步骤的四舍五入,✓
第三步:算"蒸馏"在 doc_1 的贡献(IDF = 1.22,TF = 3)
1.22×3+1.2753×(1.5+1)=1.22×4.2757.5=1.22×1.75≈2.14
日志显示 2.15,✓
第四步:doc_1 总分
3.67= 1.52∗"模型"贡献+ 2.15∗"蒸馏"贡献
八、为什么"蒸馏"贡献反而更大?
"蒸馏"在 doc_1 里的词频(TF = 3)明明低于"模型"(TF = 5),为什么贡献更大?
| IDF | TF | 饱和后的TF项 | 最终贡献 | |
|---|---|---|---|---|
| "模型" | 0.76(常见) | 5 | 1.99 | 1.52 |
| "蒸馏" | 1.22(稀有) | 3 | 1.75 | 2.15 |
"蒸馏"的 IDF 比"模型"高出约 60%,完全弥补了 TF 的差距。
这正是 BM25 的核心权衡:稀有性比出现次数更重要。一个词在文档集合里越罕见,哪怕只出现一两次,也能提供极强的区分信号。
九、稀疏检索的优势与局限
通过上面的计算,BM25(稀疏检索)的特点已经很清晰:
| 方面 | 说明 |
|---|---|
| 优势 | 精确关键词匹配,在技术术语、人名、代码等查询上表现极佳 |
| 局限 | 读不懂同义表达------查"汽车",匹配不到只写"车辆"的文档 |
这种局限正是下一步引入混合检索(稀疏 + 稠密向量)的动机:用语义向量弥补关键词匹配的盲区。
十、三个模块一句话总结
最终得分=∑每个查询词 IDF∗稀有词加权× TF+k1(⋯)TF⋅(k1+1)∗饱和的词频+长度惩罚
BM25 没有引入全新的概念,只是把 TF-IDF 的两个缺陷------线性词频 和忽略文档长度------用数学方式优雅地修掉了。
理解 BM25,是读懂稀疏检索、RAG 管道和现代搜索引擎的关键一步。