作为开发者 / 算法工程师,你一定遇到过这种情况:做搜索引擎、RAG 检索,用 TF-IDF 算相关性,结果要么长文档霸榜(明明只是顺带提了查询词),要么高频词无脑加分(提 10 次和提 20 次没区别),搜出来的结果根本不是用户想要的。
你明明只想解决「怎么精准衡量文档和查询的相关性」,却被词频、文档长度、稀有词这些因素搞得头大。
而 BM25,就是解决这个问题的「标准答案」—— 它是 Elasticsearch 默认的相似度算法,是 RAG 混合检索的核心组件,更是所有关键词检索的底层基石。
但很多人用 BM25 多年,只知道调 k1 和 b 参数,却不知道它为什么比 TF-IDF 好、词频饱和怎么实现、长度归一化的数学逻辑是什么。面试被问 BM25 原理,只能说「是 TF-IDF 的改进版」,一深究就露怯。
今天,我用第一性原理,不堆公式、不绕弯子,从最根本的问题出发,把 BM25 算法的核心逻辑讲透:它要解决什么问题、为什么这么设计、参数怎么调、实战怎么用。建议立刻收藏,不管是做检索系统、面试、还是写技术方案,都能直接用!
一、先戳痛点:TF-IDF 为什么不够用?
我们先回到最原始的场景:用户搜「人工智能应用」,你要从海量文档里找最相关的结果。
一个直观的想法是:文档里查询词出现越频繁,越相关。但这个想法很快会遇到 4 个致命问题,也是 TF-IDF 的核心缺陷:
问题 1:词频的边际效应,TF-IDF 完全没考虑
文档 A 提「人工智能」10 次,文档 B 提 20 次 ——B 真的比 A 相关两倍吗?显然不是!提 10 次已经能证明文档是讲这个主题的,再多提几次只是冗余,相关性的增益会越来越小。但 TF-IDF 里,词频是线性增长的,20 次的分数就是 10 次的两倍,完全违背直觉。
问题 2:长文档的「不公平优势」
100 字短文提「人工智能」2 次(密度 2%),1000 字长文提 5 次(密度 0.5%)—— 哪篇更相关?短文明显更聚焦,但 TF-IDF 只看绝对次数,会给长文更高分,导致「长文档霸榜」,用户想要的短而精的内容反而排后面。
问题 3:稀有词的价值,TF-IDF 没放大
「人工智能」是专业词,只出现在少数文档里,一旦出现就很关键;「的、是、在」是停用词,每篇文档都有,对相关性没贡献。TF-IDF 虽然用 IDF 加权,但 BM25 的 IDF 公式更贴合概率检索逻辑,加权效果更精准。
问题 4:查询词重复,TF-IDF 没处理
用户搜「人工智能 AI 人工智能应用」——「人工智能」出现两次,权重应该更高,但 TF-IDF 默认把查询词去重,完全忽略这种情况。
所以,BM25 要解决的根本问题只有一个:
如何设计一个打分函数,综合考虑词频饱和、文档长度、词稀有度、查询词频,给出更贴合人类直觉的相关性分数?
这也是 BM25 诞生的全部意义 —— 修复 TF-IDF 的缺陷,让关键词检索更精准。
二、从零设计:一个完美的相关性算法,需要具备什么?
不用看论文,我们从第一性原理推导,一个能解决上述问题的算法,必须满足 5 个核心需求:
需求 1:词频有收益,但「多提没用」
词频增加要加分,但超过一定次数后,每多一次的增益要递减,最终趋近上限(比如提 10 次后,再提 10 次也加不了多少分)。
需求 2:文档长度要「归一化」
同样的词频,短文档里的价值要比长文档高(密度更高),必须惩罚长文档的「绝对次数优势」。
需求 3:稀有词要「重点加权」
在文档集合中出现越少的词,区分能力越强,权重必须越高;停用词权重趋近于 0。
需求 4:查询词本身要「算权重」
查询词中重复出现的词(比如「人工智能 人工智能」),要给更高的权重,体现用户的核心诉求。
需求 5:参数可调,适配不同场景
科技论文、新闻标题、用户评论的文档特性不同,算法要能通过参数调整,适配不同场景的检索需求。
而 BM25,正是完美满足这 5 个需求的解决方案 —— 它的所有设计,都是为了让「相关性打分」更准。
三、BM25 核心原理:4 大改进,吃透底层逻辑
BM25 的设计理念很清晰:在 TF-IDF 基础上,引入非线性饱和机制和文档长度归一化,让打分更符合人类对相关性的直觉。
下面这 4 个核心改进,是 BM25 的「灵魂」,也是面试高频考点,一定要吃透。
核心 1:词频非线性饱和 —— 用 k1 解决「多提没用」
这是 BM25 对 TF-IDF 最核心的改进,核心是把「线性词频」改成「饱和词频」。
TF-IDF 的词频(线性):
plaintext
TF = 词在文档中的出现次数(f)
f=10,TF=10;f=20,TF=20—— 线性增长,完全没考虑边际递减。
BM25 的词频因子(非线性):
plaintext
TF因子 = ((k1 + 1) * f) / (k1 + f)
其中:
- f:词在文档中的出现次数
- k1:可调参数(默认 1.2),控制饱和速度
这个公式的神奇之处:
- 当 f=0 时,TF 因子 = 0(没出现的词不加分);
- 随着 f 增加,TF 因子逐渐增大,但最大值趋近于 (k1+1)(比如 k1=1.2 时,最大值≈2.2);
- f 从 0→1 的增长幅度(+1.0),远大于 f 从 10→11 的增长幅度(≈0.04)—— 完美契合「多提没用」的直觉。
举个例子(k1=1.2):
- f=1 → TF 因子 = 1.0(首次出现,增益最大);
- f=2 → TF 因子≈1.375(增益 0.375);
- f=10 → TF 因子≈1.96(增益 0.04);
- f=100 → TF 因子≈2.18(几乎不增长)。
简单说:首次出现定基调,后面多提只加一点点分。
核心 2:文档长度归一化 —— 用 b 解决「长文档霸榜」
为了惩罚长文档的「绝对次数优势」,BM25 给词频因子加了「长度修正项」:
改进后的 TF 因子:
plaintext
TF因子 = ((k1 + 1) * f) / (k1 * (1 - b + b * (dl/avgdl)) + f)
其中:
- dl:当前文档长度(词数);
- avgdl:所有文档的平均长度;
- b:可调参数(默认 0.75),控制长度影响程度。
直观理解:
- 文档长度 = 平均长度(dl/avgdl=1)→ 分母 = k1+f → 和原始公式一致,不惩罚;
- 文档长度 > 平均长度(比如 dl=2000,avgdl=1000)→ 分母变大 → TF 因子变小(惩罚长文档);
- 文档长度 < 平均长度(比如 dl=500,avgdl=1000)→ 分母变小 → TF 因子变大(奖励短文档)。
比如同样 f=5,k1=1.2,b=0.75:
- 短文档(dl=100,avgdl=1000)→ TF 因子≈4.4/(1.2*(1-0.75+0.75*0.1)+5)≈4.4/5.43≈0.81;
- 长文档(dl=2000,avgdl=1000)→ TF 因子≈4.4/(1.2*(1-0.75+0.75*2)+5)≈4.4/7.3≈0.60;
短文档的 TF 因子更高,完美体现「密度越高越相关」的直觉。
核心 3:更精准的 IDF—— 稀有词加权更合理
BM25 的 IDF 公式源于「概率检索模型」,比传统 TF-IDF 更贴合检索场景:
BM25 的 IDF 公式:
plaintext
IDF(q) = log((N - n(q) + 0.5) / (n(q) + 0.5))
其中:
- N:文档集合总数量;
- n (q):包含词 q 的文档数。
核心作用:
- 稀有词(n (q) 小)→ IDF 值高(比如「熵增定律」,只在 100 篇文档中出现,IDF≈log ((10000-100+0.5)/(100+0.5))≈log (99)≈4.6);
- 常见词(n (q) 大)→ IDF 值低(比如「的」,在 9900 篇文档中出现,IDF≈log ((10000-9900+0.5)/(9900+0.5))≈log (0.01)≈-4.6);
- 实际应用中会加平滑项(比如 log (1 + (N-n+0.5)/(n+0.5))),避免 IDF 为负。
核心 4:查询词频因子 ——k2 放大用户核心诉求
如果查询词本身有重复(比如「人工智能 AI 人工智能应用」),BM25 引入 k2 参数放大重复词的权重:
plaintext
查询词频因子 = ((k2 + 1) * qf) / (k2 + qf)
其中:
- qf:词在查询中的出现次数;
- k2:可调参数(默认 0-10),控制查询词频的影响。
比如 qf=2,k2=10:查询词频因子 =(11*2)/(10+2)=22/12≈1.83 → 重复词的权重提升 83%,更贴合用户的核心诉求。
完整的 BM25 公式
把以上所有部分组合,就是 BM25 的完整打分公式(日常用的简化版,qf=1 时):
plaintext
Score(Q, D) = ∑_{i=1}^{n} IDF(q_i) *
((k1 + 1) * f(q_i, D)) / (k1 * (1 - b + b * (|D|/avgdl)) + f(q_i, D))
简单说:每一个查询词的 IDF × 修正后的 TF 因子,全部加起来就是文档的最终相关性分数。
四、一个比喻,彻底吃透 BM25
如果把 BM25 比作「图书管理员找书」,所有逻辑就一目了然了:
- 词频饱和(k1) :一本书提「人工智能」10 次,已经能确定是相关书;提 20 次只是作者啰嗦,不会比 10 次的书「更相关两倍」—— 管理员不会因为提得多就优先推荐。
- 长度归一化(b) :300 页的书提 5 次「人工智能」,可能只是顺带提;3 页的短文提 5 次,肯定是专门讲这个主题的 —— 管理员会优先推荐短文。
- IDF 加权:用户搜「熵增定律」,这个词只在 10 本专业书里出现,管理员会重点推荐;用户搜「的」,每本书都有,这个词对找书没帮助 —— 管理员会忽略。
- 参数调节(k1/b) :科技图书馆的书都很长,管理员会调高 k1(允许词频多贡献);文学图书馆的短文更有价值,管理员会调高 b(更狠地惩罚长书)。
BM25 就像经验丰富的管理员,知道怎么平衡「次数、长度、稀有度」,给出最贴合用户需求的推荐。
五、BM25 参数调优:k1 和 b 怎么设才对?
BM25 的核心是「参数可调」,k1 和 b 的设置直接影响检索效果,记好这两张表,不用瞎试:
k1:词频饱和参数(默认 1.2)
表格
| k1 值 | 效果 | 适用场景 |
|---|---|---|
| 小(≈0.5) | 词频很快饱和,前几次出现最重要 | 短文档(标题、摘要、推文) |
| 中(1.2) | 平衡,兼顾次数和饱和 | 通用场景(网页、新闻、RAG 知识库) |
| 大(2.0+) | 词频持续贡献,多次出现仍加分 | 长文档(技术论文、书籍、专利) |
调优思路:
- 文档越长,k1 越大(长文档需要更多词频来证明相关性);
- 文档越短,k1 越小(短文档提几次就够了,多提没用)。
b:文档长度归一化参数(默认 0.75)
表格
| b 值 | 效果 | 适用场景 |
|---|---|---|
| 小(0.3) | 轻微惩罚长文档 | 文档长度差异小,或长度 = 内容深度(技术论文、书籍) |
| 中(0.75) | 中等惩罚,平衡长度和相关性 | 通用场景(网页、企业知识库) |
| 大(0.9) | 强烈惩罚长文档 | 短文档更有价值(标题、推文、用户评论) |
调优思路:
- 专业文档(论文 / 专利):长度是内容深度的体现,b 设小(别过度惩罚);
- 主观内容(评论 / 推文):短内容更精准,b 设大(狠罚长文档)。
六、BM25 的现代应用:不止是搜索引擎
BM25 不是「老算法」,而是现代检索的核心组件,这 3 个场景一定要会用:
1. Elasticsearch/Lucene(默认算法)
直接在索引设置里调参数,开箱即用:
json
{
"settings": {
"index": {
"similarity": {
"default": {
"type": "BM25",
"k1": 1.2, // 词频饱和参数
"b": 0.75 // 长度归一化参数
}
}
}
}
}
2. RAG 混合检索(BM25 + 向量检索)
这是当前最主流的检索方案,互补性拉满:
- BM25:擅长关键词匹配,对「精确词」敏感(比如用户搜「年假申请流程」,能精准匹配手册里的关键词);
- 向量检索:擅长语义理解,能处理同义词(比如「年假怎么批」和「年假申请流程」是一个意思);两者结合,召回率和精准度能提升 30% 以上。
3. Milvus 向量数据库(稀疏向量检索)
Milvus 支持 BM25 稀疏向量,适合混合检索:
python
运行
from pymilvus.model.sparse import BM25EmbeddingFunction
# 初始化分析器(支持中文)
analyzer = build_default_analyzer(language="zh")
# 实例化BM25嵌入函数
bm25_ef = BM25EmbeddingFunction(analyzer)
# 拟合语料库(计算IDF)
bm25_ef.fit(corpus)
# 文档转稀疏向量
sparse_vectors = bm25_ef.encode_documents(documents)
# 查询转稀疏向量
query_vector = bm25_ef.encode_queries(["人工智能应用"])
七、BM25 的本质:不止是算法,更是检索的「底层逻辑」
用第一性原理看,BM25 的本质是:
一个基于概率检索理论的词项加权函数,通过非线性词频饱和和文档长度归一化,修正 TF-IDF 的缺陷,更精准地估计文档与查询的相关性。
它的核心贡献是 4 个「认知升级」:
- 从线性到非线性:认识到词频的相关性增益是边际递减的,不是越多越好;
- 从绝对到相对:认识到词频的价值取决于文档长度,密度比绝对次数更重要;
- 从固定到灵活:认识到不同场景需要不同的打分规则,通过参数适配业务;
- 从经验到理论:所有公式都源于概率检索模型,不是凭空捏造,有坚实的理论基础。
八、总结:BM25 的 5 大核心价值,检索工程师必记
表格
| 核心价值 | 解决的问题 | 实现方式 |
|---|---|---|
| 词频非线性饱和 | TF-IDF 线性词频,多提没用却加分 | 引入 k1,TF 因子趋近 (k1+1) |
| 文档长度归一化 | 长文档霸榜,短文档被埋没 | 引入 b 和 dl/avgdl,惩罚长文档 |
| 稀有词精准加权 | 常见词干扰检索结果 | 概率版 IDF 公式,稀有词权重更高 |
| 参数灵活可调 | 一刀切的算法适配不了所有场景 | k1(词频)、b(长度)、k2(查询)可配置 |
| 理论 + 实战兼备 | 算法无理论支撑,效果不稳定 | 源于二元独立模型,是 ES/Milvus 默认算法 |
其实 BM25 一点都不复杂,它的所有设计,都是为了解决「怎么更准地衡量相关性」这个根本问题。当你理解这一点,再看 k1、b、IDF 这些细节,就会发现一切都是顺理成章的。
互动话题:你用 BM25 时,踩过最坑的问题是什么?
相信很多做检索 / 搜索引擎的同学,用 BM25 时都遇到过各种坑:比如调不好 k1/b 导致检索结果跑偏、中文分词影响 BM25 效果、混合检索时 BM25 和向量检索权重怎么分配……
评论区留言说说:你用 BM25 时,踩过最坑的一个问题是什么?最后怎么解决的?
我会在评论区挑选 10 个高频坑,下次专门写一篇《BM25 高频踩坑指南》,帮大家一次性解决所有痛点!
另外,点赞 + 收藏这篇文章,私信我回复「BM25」,免费领取《BM25 实战手册》(含 ES/Milvus 配置、参数调优案例、混合检索代码),帮你快速落地 BM25,检索效果翻倍!