BM25 与 Lucene Similarity:公式如何落到 postings

8 阅读2分钟

原文发布于 quant67.com,转载请保留出处。

Postings 与 codec 把词项如何编码成可跳跃的 docID/freq 列表讲清了;查询侧还要回答:两个文档都包含关键词,凭什么 A 排在 B 前面? 这不是 UI 偏好,而是 Similarity 在 postings 上为每个 (query term, docID) 算出的分数如何累加。

本文是「全文检索引擎」系列第 6 篇。目标不是复述信息检索教材,而是钉住三条链:

  1. Robertson & Zaragoza (2009) 的 BM25 公式与参数 k1k_1bb 各自抑制什么失效模式;
  2. Lucene BM25Similarity 如何把 avgdl、norms、IDF 接到 第 5 篇 的 postings 访问路径上;
  3. BM25 作为可解释基线,与学习排序(LTR)在生产里分工在哪里。

版本锚定:Apache Lucene 9.x / 10.xorg.apache.lucene.search.similarities.BM25Similarity);Elasticsearch 8.x 默认 similarity: BM25。公式以 Robertson & Zaragoza, The Probabilistic Relevance Framework: BM25 and Beyond, FnTIR 2009 为准。


一、问题从哪来:TF 线性增长为何在工程上失效

经典向量空间模型里,词频 TF 常线性进入打分:同一词出现越多,文档越「相关」。这在短查询、长短文档混杂的 Web 语料上很快失效:

  • 词频饱和:第 10 次出现「database」带来的边际相关性远低于第 1 次;
  • 长度偏置:长文档天然更容易累积高 TF,把真正聚焦主题的短文挤下去。

BM25(Best Matching 25)来自 Robertson & Walker 等在 Okapi 系统上的概率相关框架;Robertson & Zaragoza (2009) 把它整理为 PRF 教程中的标准写法,并讨论 Beyond BM25 的扩展。Lucene 自 6.0 起把默认 Similarity 从 TF-IDF 切到 BM25——这不是「新算法噱头」,而是把饱和 TF + 长度归一写进默认路径。


二、BM25 公式与参数语义

对查询 QQ、文档 DD,设 f(q,D)f(q,D) 为词项 qqDD 中的词频,D|D| 为文档长度(通常用该字段总词数),avgdl\mathrm{avgdl} 为索引内同字段平均文档长度,NN 为文档总数,nqn_q 为包含 qq 的文档数。Robertson & Zaragoza (2009) 给出的 BM25 项级打分可写为:

score(q,D)=IDF(q)f(q,D)(k1+1)f(q,D)+k1(1b+bDavgdl)\mathrm{score}(q, D) = \mathrm{IDF}(q) \cdot \frac{f(q,D)\,(k_1 + 1)}{f(q,D) + k_1 \cdot \left(1 - b + b \cdot \dfrac{|D|}{\mathrm{avgdl}}\right)}

查询总分对 QQ 中各 qq 求和(Lucene 默认对多词查询按词项分数相加,具体组合由 BooleanQuery 与协调因子决定,见 第 9 篇)。

IDF 在 Lucene BM25Similarity 中使用 Robertson-Spark Jones 风格平滑:

IDF(q)=ln(1+Nnq+0.5nq+0.5)\mathrm{IDF}(q) = \ln\left(1 + \frac{N - n_q + 0.5}{n_q + 0.5}\right)

(自然对数;实现里对负 IDF 截断为 0。)

符号 / 参数典型值(Lucene 默认)抑制什么
k1k_11.2TF 饱和速度:越大,高频词越晚「封顶」
bb0.75长度归一强度:b=0b=0 忽略长度;b=1b=1 完全按 $D/\mathrm{avgdl}$ 惩罚
avgdl\mathrm{avgdl}索引统计把绝对长度变成相对平均长度的比值
IDF\mathrm{IDF}N,nqN, n_q常见词降权、稀有词升权,但带平滑避免 nq=0n_q=0 爆炸

2.1 TF 饱和的曲线形状

固定 k1=1.2k_1=1.2、长度因子为 1 时,TF 贡献 f(k1+1)f+k1\dfrac{f(k_1+1)}{f+k_1}ff 单调增但渐近上限为 k1+1k_1+1。这与 TF-IDF 里 TF 未饱和(或仅 tf\sqrt{\mathrm{tf}} 等弱饱和)形成鲜明对比——也是「长文堆砌关键词」在 BM25 下更难刷分的根因。

flowchart LR
  subgraph tf ["TF leg"]
    f["freq from postings"]
    sat[&#34;saturating fn<br/>k1=1.2&#34;]
    f --> sat
  end
  subgraph len [&#34;Length leg&#34;]
    dl[&#34;doc length |D|&#34;]
    norm[&#34;norms byte&#34;]
    avg[&#34;avgdl stats&#34;]
    dl --> norm
    avg --> sat
    norm --> sat
  end
  subgraph idf [&#34;IDF leg&#34;]
    N[&#34;total docs N&#34;]
    nq[&#34;doc freq nq&#34;]
    idf[&#34;ln smoothed IDF&#34;]
    N --> idf
    nq --> idf
  end
  sat --> sum[&#34;term score&#34;]
  idf --> sum

三、Lucene 落点:BM25Similarity、norms 与 avgdl

3.1 索引期:norms 编码字段长度

Lucene 在索引带 IndexOptions 的文本字段时,默认写入 norms(每文档每字段一字节),编码该字段长度信息供打分使用。BM25SimilaritycomputeNorm 中把 token 计数映射为可被 $b$ 使用的长度因子——查询期不再扫描全文数词,只需读 norms 与 postings 里的 freq

这与 第 2 篇 的字段正交开关一致:omitNorms=true 会去掉长度归一(所有文档长度因子视为 1),适合长度分布极均匀或刻意不做长度惩罚的场景。

3.2 查询期:CollectionStatistics 与 avgdl

打开 IndexSearcher 时,BM25SimilarityCollectionStatistics 读取 NN、总词数等,计算:

avgdl=sumTotalTermFreqdocCount\mathrm{avgdl} = \frac{\text{sumTotalTermFreq}}{\text{docCount}}

(对应该字段;多段索引时由 reader 聚合段统计。)每个 (term, doc) 的打分在 Scorer 里按需计算:从 postings 取 freq,从 norms 解码长度,再套上一节的公式。

3.3 与 explain 对齐

Elasticsearch _explain 与 Lucene Explanation 会展开 idftffieldNorm 等子项——排障时应对照公式逐项核对,而不是只看最终 _score。本系列不在此粘贴未在本机执行的 explain 输出;读者可在单节点用官方文档中的 explain API 自行核对。

组件索引期查询期
postings freq写入读取 f(q,D)f(q,D)
norms编码 D\|D\|解码长度因子
词典 docFreq写入 nqn_q计算 IDF
段/索引统计NNavgdl\mathrm{avgdl}

四、与 TF-IDF 的工程差异

Lucene 仍提供 ClassicSimilarity(传统 TF-IDF 风格)供显式切换;Elasticsearch mapping 里也可设 similarity: boolean 等。对照 BM25,工程上应记住:

维度Classic / TF-IDF 路径BM25 默认路径
TFtf\sqrt{\mathrm{tf}} 或未饱和线性显式饱和,上限由 k1k_1 控制
长度lengthNorm 乘子bbavgdl\mathrm{avgdl} 进入 TF 分母
稀有词IDF同族 IDF 平滑,但 TF 腿不同
默认历史默认Lucene 6+ / ES 现代默认

争论(有文献支撑):BM25 在 TREC 类 ad-hoc 检索上长期作为强基线(Robertson & Zaragoza 2009 综述);但在域内排序(电商、招聘)上,手工特征 + 学习排序常能压过纯 BM25——前提是标注数据、特征管线与 serving 成本可承受。BM25 的价值在于:零训练、可解释、与 postings 紧密耦合、延迟可预测

4.1 常见误解

  1. 「BM25 的 IDF 就是 ln(N/nq)\ln(N/n_q)。Lucene 实现用 (Nnq+0.5)/(nq+0.5)(N-n_q+0.5)/(n_q+0.5) 平滑;与教科书简化式数值不同,explain 里应对 implementation 而非背错公式。
  2. 「调大 k1k_1 一定提升召回」k1k_1 只改 TF 饱和形状;极端大 k1k_1 接近线性 TF,重新引入堆砌关键词偏置。
  3. 「similarity 只影响排序,不影响倒排」。Similarity 不改 postings 编码,但 norms 在索引时写入;改 bb 或换 Similarity 类通常需 reindex 才能一致生效(除非仅 IDF 腿且 norms 未变)。

五、与学习排序的工程边界

学习排序(Learning to Rank, LTR)把相关性变成监督学习:LambdaMART、RankNet 等在特征向量上训练,再在生产对候选文档重排。代表工作包括 Burges (2010) 对 LTR 的综述,以及后续将 BM25 分数、字段匹配、点击信号等作为特征的工业实践。

flowchart TB
  q[&#34;User query&#34;]
  recall[&#34;Recall layer<br/>BM25 / Boolean / kNN&#34;]
  cand[&#34;Candidate docIDs<br/>top N per shard&#34;]
  feat[&#34;Feature extraction<br/>BM25 score, boosts, DV&#34;]
  ltr[&#34;LTR model optional&#34;]
  out[&#34;Final ranking&#34;]
  q --> recall --> cand --> feat
  feat --> out
  feat --> ltr --> out

工程分界(本系列立场,非学术终局判断):

典型实现BM25 角色
召回match / dis_max / 混合 kNN主力或强特征;决定候选集是否漏 doc
粗排分片内 Top-KBM25 分数直接截断
精排ES rescore、外部 LTRBM25 常作特征之一,非唯一分数
RAG 稀疏路llm-infra 召回BM25 零训练、易复现;语义缺口由向量路补

工程间隙:论文里的 LTR 常在固定候选集上测 NDCG;生产里 候选集由 BM25 先砍到 Top-N,LTR 再精排——BM25 参数恶化会造成功能性漏召回,精排模型救不回来。Elasticsearch 的 sltr 插件与外部 rerank 服务把模型 serving 挪出 Lucene 核心;Lucene Similarity 接口仍是嵌入式场景的扩展点,但大多数 ES 用户不会改 Java Similarity,而是改 boost、function_score 或二次 rescore。

开放问题

  1. 稠密检索 + BM25 融合 的统一打分函数尚无社区共识(见本系列 第 15 篇)。
  2. 跨语言 / 多字段avgdl\mathrm{avgdl}bb 是否应字段级定制,仍依赖域内评测而非单一全局默认。
  3. LLM 重排 成本与延迟下,BM25 粗排窗口该多大,缺少与硬件无关的普适公式。

5.1 Elasticsearch 侧如何改 BM25

Elasticsearch mapping 允许字段级 similarity

{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "similarity": "BM25",
        "index_options": "positions"
      }
    }
  }
}

BM25 类型可配 k1b(8.x Reference Similarity)。修改后 仅影响后续索引 的 norms 与统计;已有段仍按旧参数写入的 norms 解释。全索引统一需 reindex 或 rollover 新索引——这与「只改查询 DSL」完全不同。

bool 查询里的 boost 乘在 Lucene 子句 Weight 上,不改变 IDF 公式本身function_score 可把 BM25 分与 DocValues 字段组合(见 第 10 篇),已超出纯 Similarity 范畴。


六、调参与失效模式(无 benchmark 结论)

下列判断来自机制推导与官方文档,非本机吞吐排名

  • 新闻 / 日志:文档长度方差大,保持默认 b=0.75b=0.75 通常合理;极短字段(标题)可单独字段并视情况 omitNorms 或降低 bb
  • 词典字段(SKU、ISBN):长度几乎恒定,norms 收益低;更应依赖精确词项与 boost。
  • 多语言混合索引avgdl\mathrm{avgdl} 对「中文长文 + 英文摘要」同字段混合时会失真——优先 分字段 而非只调 k1k_1

6.1 与向量引擎 / RAG 的分工

llm-infra 第 17 篇 在应用层组合 BM25 与向量召回;向量检索引擎系列 专讲 ANN 索引与 Segment 生命周期。本系列第 6 篇只钉 BM25 在 Lucene 内的落点,三者分工如下:

flowchart LR
  q[&#34;Query&#34;] --> sparse[&#34;BM25 on postings<br/>this series&#34;]
  q --> dense[&#34;kNN on dense_vector<br/>vector-engine&#34;]
  sparse --> fuse[&#34;RRF / rescore / LTR<br/>llm-infra 17&#34;]
  dense --> fuse
  fuse --> ctx[&#34;Context to LLM&#34;]
环节BM25(引擎层)向量 ANNRAG 应用层
召回依据词项共现、IDFembedding 几何近邻chunk 边界、metadata 过滤
必用场景SKU、法规号、日志 keywordparaphrase、跨语言语义prompt 窗口、citation
调试入口_explain、AnalyzerefSearch、索引度量融合权重、rerank 延迟
典型漏召回分词未产出 query term域外向量、错误 embedding 模型chunk 切断实体

引擎侧应明确:

环节BM25 作用常见坑
chunk 索引按 chunk 字段算 avgdl\mathrm{avgdl}父文档过长导致 chunk norms 失真
hybridBM25 与 kNN 分数量纲不同rank_window_size / RRF 等融合,非直接相加(见 第 15 篇
explain调试漏召回先看是否 未索引到词项(Analyzer),再看 IDF/TF

BM25 不能保证语义等价(「汽车」vs「车辆」),这是 向量路或 LTR 存在的理由,不是 BM25 实现缺陷;反之,向量路不能保证 必须出现某 token 的合规检索——RAG 生产链路应默认 双路召回 + 显式融合,而非单路替代。


七、小结

三句话小结

  1. BM25 用 饱和 TF + avgdl\mathrm{avgdl} 长度归一 + 平滑 IDF 解决线性 TF 与长文偏置,公式以 Robertson & Zaragoza (2009) 为准,Lucene 在 BM25Similarity 中落到 postings/norms/段统计。
  2. norms 索引期写入、avgdl 查询期聚合——改 Similarity 往往意味着 reindex,不能只当查询侧开关。
  3. 生产里 BM25 仍是 召回与可解释基线;LTR/LLM 精排在候选集之上工作,不能替代 postings 相交与截断层。

下一篇看写入路径如何把新文档变成可搜段:IndexWriter 与 NRT


参考资料

论文 / 教程

  1. Robertson, S. & Zaragoza, H., The Probabilistic Relevance Framework: BM25 and Beyond, Foundations and Trends in Information Retrieval, 2009(BM25 公式与 PRF 谱系)。
  2. Robertson, S. & Walker, S., Some Simple Effective Approximations to the 2-Poisson Model for Probabilistic Weighted Retrieval, SIGIR 1994(Okapi/BM25 源头之一)。
  3. Burges, C. J. C., From RankNet to LambdaRank to LambdaMART: An Overview, Microsoft Technical Report 2010(LTR 工程特征常含 BM25 分)。

规范 / 源码

  1. Apache Lucene 9.x/10.x Javadoc:org.apache.lucene.search.similarities.BM25SimilarityClassicSimilaritySimilarity
  2. Elasticsearch 8.x Reference:Mapping parameterssimilaritynormsExplain API

站内

  1. Postings codec混合检索查询执行系列目录
  2. 向量检索引擎RAG 工程化(应用层融合分工)。

返回 系列目录 | 上一篇:Postings codec | 下一篇:IndexWriter NRT