从零构建现代搜索引擎(E01):学习稀疏检索
BM25 靠精确词匹配召回文档。用户搜"怎样并行处理",文档里写的是"多线程编程"——BM25 一条也召不回来。dense retrieval 用向量弥补词汇鸿沟,但丢掉了精确匹配的优势:搜错误码 NullPointerException,dense 模型可能把它和所有异常类文档混在一起。
学习稀疏检索(learned sparse retrieval)试图兼得两头:保留倒排索引的精确匹配和可解释性,同时用模型扩展词汇覆盖范围。
词汇鸿沟的代价
回顾 BM25 的召回逻辑:query 中的 term 必须出现在文档中,文档才能进入候选集。这意味着:
- 同义词缺失:用户搜"取消订单",文档写的是"订单退回"→ 无命中
- 上下位词:搜"数据库",文档讨论的是"PostgreSQL"→ 无命中
- 缩写/全称:搜"JVM",文档写的是"Java 虚拟机"→ 无命中
传统解法是同义词表。第 13 篇介绍的同义词扩展能缓解部分问题,但人工维护同义词表的成本随词汇量指数增长,且无法覆盖领域内的新术语和上下文相关的语义关系。
SPLADE:用 MLM 头生成 term 权重
SPLADE(Formal et al., 2021)的核心思路:把 BERT 的 Masked Language Model 头拿来给每个 term 打权重。
训练阶段
给定一段文本(query 或 document),SPLADE 做以下操作:
- 文本输入 BERT encoder,得到每个 token 位置的上下文向量
- 每个上下文向量过 MLM head,输出词表大小(如 30,522)的 logits
- 对所有 token 位置的 logits 取 max-pooling,得到一个词表大小的向量
- 对这个向量取 ReLU + log(1+x),生成稀疏的 term 权重
1 | |
关键观察:模型不只给原文 term 打权重,还"扩展"出了语义相关但原文不存在的 term。这正是 BM25 做不到的——模型在训练中学会了 term 之间的关联。
FLOPS 正则化
如果不加约束,模型可能给所有 term 都赋予非零权重——这就退化成了 dense retrieval,失去稀疏索引的效率优势。
SPLADE 通过 FLOPS regularization 控制稀疏度:
1 | |
其中 w_ij 是第 i 个文档在第 j 个 term 上的权重。这个正则项惩罚在整个 batch 中普遍出现的 term(类似 IDF 的逆文档频率思想),迫使模型只保留区分性强的 term。
典型超参数下,每个文档的非零 term 数在 128-256 之间。
索引与检索
SPLADE 生成的稀疏向量可以直接存入倒排索引:
1 | |
检索时:
- query 也过 SPLADE 模型,生成稀疏 term 权重
- 用 query 的非零 term 查倒排表
- 对每个候选文档,相关性 = Σ(query_term_weight × doc_term_weight)
整个流程复用倒排索引的基础设施:skip list、WAND 剪枝、Top-K 堆——第 7-11 篇建立的所有结构都能直接用。
Lucene 中的实现路径
Lucene 的 FeatureField 可以存储 learned sparse 权重:
1 | |
1 | |
FeatureField 在 Lucene 内部用跳表结构存储,支持高效的 Top-K 查询。
三路融合实验
在主线的 BM25 + dense + RRF 基础上,加入 learned sparse 变成三路:
1 | |
RRF 公式不变,只是从两路变三路:
1 | |
对比实验设计
| 组合 | nDCG@10 变化预期 | 额外成本 |
|---|---|---|
| BM25 only | 基线 | 无 |
| BM25 + dense | +15-25% | embedding 推理 |
| BM25 + sparse | +10-15% | SPLADE 推理 + 索引 |
| BM25 + dense + sparse | +20-30% | 两套模型推理 + 两套索引 |
三路融合通常能在两路基础上再提 3-8%——收益递减,但对长尾查询(专业术语、罕见搭配)的提升最明显。
中文 learned sparse 的现实
中文 learned sparse 模型的公开选择有限。几个可用方向:
BGE-M3(BAAI, 2024)同时输出 dense、sparse 和 ColBERT 三种表示,是目前最直接的中文 learned sparse 来源。sparse 输出的 term 权重可以直接存入 FeatureField。
自训练路线:基于中文 BERT 加 MLM head,在领域数据上微调 SPLADE。需要对比查询对(正负样本)和足够的训练数据。对于本系列的 100 篇小语料,自训练不现实。
务实选择:如果语料规模小且领域集中,BM25 + dense 的两路融合已经覆盖大部分收益。learned sparse 的边际收益在大规模、宽领域的场景中更显著。
可解释性
learned sparse 相对 dense retrieval 的一个独特优势是可解释性。当用户问"为什么这篇文档排在第一"时:
1 | |
每个 term 的贡献清晰可见——这在 debug 搜索质量时很有价值。
练习
- 用 FeatureField 为种子语料的每篇文档存储手工 term 权重(模拟 SPLADE 输出),验证检索是否正确
- 对比 BM25 和手工 sparse 权重在同义词查询上的召回差异
- 设计一个实验:固定 query 集,分别测 BM25、dense、模拟 sparse 的 nDCG@10,计算三路 RRF 融合的提升
延伸阅读
- Formal et al., “SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking”, SIGIR 2021
- Formal et al., “From Distillation to Hard Negative Sampling: Making Sparse Neural IR Models More Effective”, SIGIR 2022
- Xiao et al., “BGE-M3: Multi-lingual, Multi-functionality, Multi-granularity Text Embeddings Through Self-knowledge Distillation”, 2024
- Lucene FeatureField Javadoc






