状态:已实现 | 路径:快速离线;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 分数没有固定上界,不能直接和余弦分数相加。
- 小数据上改变参数可能不改变排名,不代表参数无效。
- 为什么一个词在所有文档中都出现时区分力低?
- 什么时候应该降低
b?
参考答案
df≈N时 IDF 较小,它不能区分文档。2. 当文档长度差异来自格式而不是信息量,或长文档不应被强惩罚时,可降低长度归一化强度,但必须通过固定评估集验证。
- 能解释
tf/df/avgdl。 - 能构造一个稠密检索容易漏、BM25 容易找的查询。
- 不直接混加 BM25 与余弦原始分数。
- Robertson and Zaragoza, BM25 and Beyond.
上一章:06|残差 IVF-PQ | 下一章:08|混合检索与重排