Skip to content

Latest commit

 

History

History
73 lines (46 loc) · 2.63 KB

File metadata and controls

73 lines (46 loc) · 2.63 KB

07|BM25

状态:已实现 | 路径:快速离线;C++ 不可用时有 Python 回退

学习目标与先修知识

  • 理解 BM25 为什么擅长型号、人名、API 名和精确术语。
  • 掌握 TF 饱和、IDF 和文档长度归一化。
  • 能解释中文分词如何改变倒排索引。

当前实现边界

SparseRetriever 使用 jieba 分词,优先调用 C++ BM25Index,导入失败时退回纯 Python。两条路径使用同一公式,但删除功能只在 C++ 路径调用,课程不把回退实现描述成完全等价的生产后端。

概念直觉与核心公式

对查询词 t 和文档 D

score(D,Q) = Σ_t IDF(t) · tf(t,D)(k1+1)
             / [tf(t,D) + k1(1-b+b|D|/avgdl)]

IDF(t) = log((N-df(t)+0.5)/(df(t)+0.5)+1)
  • k1 控制词频从“继续有用”到“逐渐饱和”的速度。
  • b=0 不做长度归一化,b=1 使用完整长度归一化。
  • 稀有词 df 小,IDF 更大;这使精确型号更突出。

项目调用链

  • SparseRetriever.add_chunks():jieba → token list → C++/Python postings。
  • C++ BM25Index:记录 postings、文档长度和平均长度。
  • search():查询分词 → 累加词项分数 → 映射回 Chunk。
  • 测试:tests/test_phase2_python.py 和检索管道测试。

最小实验

python examples/learning/run_lab.py --lab 07

预期现象:包含稀有型号 X100 的 Chunk 排在前面。修改实验中的 k1/b 后,短文档与重复词文档的相对分数可能变化。

常见错误、边界与反例

  • BM25 不理解同义词;“汽车”不一定找到只写“轿车”的文档。
  • 分词器把型号拆错时,公式再正确也无法精确召回。
  • BM25 分数没有固定上界,不能直接和余弦分数相加。
  • 小数据上改变参数可能不改变排名,不代表参数无效。

练习

  1. 为什么一个词在所有文档中都出现时区分力低?
  2. 什么时候应该降低 b
参考答案
  1. df≈N 时 IDF 较小,它不能区分文档。2. 当文档长度差异来自格式而不是信息量,或长文档不应被强惩罚时,可降低长度归一化强度,但必须通过固定评估集验证。

完成检查

  • 能解释 tf/df/avgdl
  • 能构造一个稠密检索容易漏、BM25 容易找的查询。
  • 不直接混加 BM25 与余弦原始分数。

原始资料

上一章:06|残差 IVF-PQ | 下一章:08|混合检索与重排