深入 Elasticsearch(07):BM25 与打分机制
上一篇解决了搜索的执行流程——Query-Then-Fetch 两阶段在集群中怎样运转。这一篇进入每条结果的分数是怎么算出来的。
ES 的搜索结果按 _score 降序排列。_score 是 BM25 算法算出的相关性分数。理解 BM25,才能理解为什么有些文档排在前面、有些排在后面,也才能有针对性地调整搜索相关性。
本文只抓一个问题:BM25 的三个因子分别衡量什么,以及它们怎样组合成最终分数。
BM25 的直觉
BM25 的名字来自"Best Matching 25"(第 25 号最佳匹配公式)。它取代了 ES 5.x 之前使用的 TF-IDF 模型,成为 Lucene 和 ES 的默认相似度算法。
BM25 的核心思路可以用一句话概括:一个词项越稀有(IDF 高)、在文档中出现越多次(TF 高)、文档越短(字段长度归一化),包含这个词项的文档就越相关。
分数由三个因子相乘构成:
1 | |
flowchart TB
IDF["IDF<br/>词项在多少文档中出现?<br/>越稀有 → 值越高"]
TF["TF 饱和<br/>词项在本文档出现几次?<br/>边际递减, 有上界"]
LN["字段长度归一化<br/>文档有多长?<br/>越短 → 信号越强"]
SCORE(("最终 score"))
IDF -->|×| SCORE
TF -->|×| SCORE
LN -->|×| SCORE
K1["k1 (默认 1.2)<br/>控制 TF 饱和速度"] -.-> TF
B["b (默认 0.75)<br/>控制长度惩罚力度"] -.-> LN
三个因子各回答一个独立问题:这个词稀不稀有、在这篇文档里出不出现得多、这篇文档本身长不长。下面逐一拆解。
因子一:IDF——逆文档频率
IDF 衡量一个词项的稀有程度。在 10000 篇文档中只出现在 5 篇里的词(如 “elasticsearch”)比出现在 8000 篇里的词(如 “the”)信息量大得多。
IDF 的计算:
1 | |
当一个词在大量文档中出现时,df 接近 N,IDF 趋近于 0——这个词对区分文档几乎没有贡献。当一个词只在少数文档中出现时,IDF 值较高——这个词有很强的区分能力。
因子二:TF 饱和——词频的边际递减
TF(term frequency)衡量一个词在文档中出现的次数。出现 5 次比出现 1 次更相关,但出现 50 次不应该比出现 5 次相关 10 倍——边际收益递减。
BM25 的 TF 饱和函数:
1 | |
k1 控制词频饱和的速度。k1 越大,高词频的文档获得的额外分数越多(饱和越慢)。k1 = 0 时词频完全不影响分数。
旧版 TF-IDF 使用 √tf 作为词频因子,没有上界——词频越高分数越高,没有饱和。BM25 的饱和函数在 tf 增大时趋近于 (k1 + 1),有明确的上界。
因子三:字段长度归一化
b 参数控制字段长度对分数的影响。一个词在 100 词的短文档中出现 1 次,比在 10000 词的长文档中出现 1 次更有信号量——短文档中每个词的密度更高。
b = 1:完全按字段长度归一化。短文档获得显著加分。b = 0:忽略字段长度。所有文档不论长短,同等对待。b = 0.75(默认):在两者之间取平衡。
字段长度信息存储在 segment 的 norms 文件中。如果禁用 norms("norms": false),BM25 就无法做长度归一化。
用 explain 读懂分数
explain API 会把 BM25 的计算过程展开成一棵树。多词查询时,顶层是各词项分数的加和;每个词项内部是 IDF 和 TF_saturation 的乘积。
flowchart TD
ROOT["score = sum of term scores"]
T1["term: 'search'"]
T2["term: 'engine'"]
ROOT --> T1
ROOT --> T2
IDF1["idf = 0.6931"]
TF1["tf_sat = 0.4545<br/>k1=1.2, b=0.75<br/>dl=6, avgdl=7"]
S1["term score = 0.3151"]
T1 --> IDF1
T1 --> TF1
IDF1 --> S1
TF1 --> S1
IDF2["idf = ..."]
TF2["tf_sat = ..."]
S2["term score = ..."]
T2 --> IDF2
T2 --> TF2
IDF2 --> S2
TF2 --> S2
把 explain: true 加到搜索请求中就能拿到这棵树:
1 | |
返回结果中每个 hit 会包含 _explanation 字段,结构类似:
1 | |
读 explain 输出的要点:
- 最外层是各词项分数的加和(多词搜索时)
- 每个词项的分数 = IDF × TF_saturation
- TF_saturation 内部包含了 k1、b、dl(当前文档字段长度)、avgdl(平均字段长度)
- 可以直接看到哪个因子贡献了主要分数
调整打分行为
ES 提供几种方式调整打分:
通过 index settings 修改 BM25 参数:
1 | |
通过 function_score 在 BM25 分数基础上叠加自定义打分逻辑(如时间衰减、热度加权)。通过 script_score 用脚本完全自定义打分公式。这些高级打分机制超出本篇范围,核心要理解的是 BM25 提供了基线分数。
实验:观察长度归一化效果
写入三个不同长度的文档,搜索同一个词,用 explain 观察分数差异:
1 | |
搜索 “search”:
1 | |
三条文档都包含 “search” 一次(tf=1),IDF 相同。分数差异完全来自字段长度归一化:doc1(2 词)的分数最高,doc3(约 16 词)的分数最低。这就是 BM25 的 b 参数在起作用——短文档中出现同一个词,权重更高。
模式提炼:统计打分模型
1 | |
BM25 属于"词袋模型"(bag of words)——它不考虑词项在文档中的位置和顺序,只考虑词项的统计特征。这是信息检索领域最成熟的统计打分框架。
| 因子 | 衡量什么 | 直觉 |
|---|---|---|
| IDF | 词项在全局的稀有程度 | 稀有的词更有区分力 |
| TF | 词项在文档中的出现频率 | 出现越多越相关,但有饱和上界 |
| 长度归一化 | 文档的字段长度 | 短文档中的匹配信号更强 |
工程迁移表
| 概念 | Elasticsearch BM25 | Solr BM25 | Lucene Similarity | 搜索广告 CTR 预估 |
|---|---|---|---|---|
| 基础模型 | BM25(默认) | BM25(默认,可切回 TF-IDF) | BM25Similarity | 逻辑回归 / 深度模型 |
| 词频处理 | 饱和函数(k1) | 饱和函数(k1) | 同 ES | 特征工程 |
| 稀有度 | IDF | IDF | IDF | 无直接对应(CTR 特征) |
| 长度归一化 | b 参数 + norms | b 参数 + norms | norms | 无直接对应 |
| 自定义打分 | function_score / script_score | boost / rerank | 自定义 Similarity | 模型权重 |
常见误解
误解一:BM25 分数可以跨查询比较。 不同查询的 BM25 分数没有可比性。查询 “search” 的 1.5 分和查询 “database” 的 2.0 分不能直接比较,因为 IDF 不同。BM25 分数只在同一次查询的结果列表内有意义。
误解二:分数高就表示文档更好。 BM25 衡量的是文本层面的词汇匹配度,不是"质量"或"权威性"。一个垃圾文档如果刚好高频包含查询词,分数可能比权威文档更高。这就是为什么实际搜索系统通常在 BM25 基础上叠加额外的排序信号(如 PageRank、热度、时效性)。
误解三:所有字段都参与打分。 只有 query context 中的查询参与打分。filter context 中的查询只做过滤,不贡献分数。
练习
-
创建一个单 shard 的 index,写入 5 条不同长度的文档(都包含同一个关键词),用
explain: true搜索这个词,验证 BM25 的长度归一化效果——短文档分数更高。 -
修改 index 的 BM25 参数,分别设
b=0(禁用长度归一化)和b=1(最大化长度归一化),对比搜索结果排序的变化。 -
写入一条文档让某个词出现 1 次、3 次、10 次、50 次,用 explain 观察 TF 饱和效果——50 次出现的分数并不比 10 次高很多。
系列导航
| 上一篇 | 下一篇 |
|---|---|
| 搜索执行模型:Query-Then-Fetch 的两阶段流程 | Query DSL 深入:从 match 到 bool 的查询体系 |
参考资料
- Elasticsearch 官方文档:Similarity Module
- Elasticsearch 官方文档:Explain API
- Christopher D. Manning, Prabhakar Raghavan, Hinrich Schütze. Introduction to Information Retrieval. Cambridge University Press.(第 6 章、第 11 章:BM25 与概率检索模型)
- Stephen Robertson, Hugo Zaragoza. “The Probabilistic Relevance Framework: BM25 and Beyond.” Foundations and Trends in Information Retrieval, 2009.
