ElasticSearch核心引擎Apache Lucene(五):相关性算分 (Scoring)

文章目录

    • [1. 知识导图:Lucene 评分体系概览](#1. 知识导图:Lucene 评分体系概览)
    • [2. 传统霸主:TF-IDF 算法原理](#2. 传统霸主:TF-IDF 算法原理)
      • [2.1 核心公式拆解](#2.1 核心公式拆解)
      • [2.2 TF-IDF 的致命缺陷](#2.2 TF-IDF 的致命缺陷)
    • [3. 现代标准:BM25 (Best Matching 25)](#3. 现代标准:BM25 (Best Matching 25))
      • [3.1 BM25 vs TF-IDF 曲线对比](#3.1 BM25 vs TF-IDF 曲线对比)
      • [3.2 BM25 核心公式](#3.2 BM25 核心公式)
      • [3.3 关键参数详解 ( k 1 k_1 k1 与 b b b)](#3.3 关键参数详解 ( k 1 k_1 k1 与 b b b))
        • [流程图:BM25 计算逻辑](#流程图:BM25 计算逻辑)
    • [4 实战:如何在 Elasticsearch 中掌控评分](#4 实战:如何在 Elasticsearch 中掌控评分)
      • [4.1 Explain API:调试神器](#4.1 Explain API:调试神器)
      • [4.2 自定义参数配置](#4.2 自定义参数配置)
    • 总结

引言

Elasticsearch (ES) 之所以能在海量数据中实现毫秒级的搜索响应,归功于其底层坚实的基石------Apache Lucene。如果说倒排索引(Inverted Index)是 Lucene 的骨架,那么**相关性打分(Scoring)**就是它的灵魂。

为什么搜索 "Apple" 时,展示的是苹果手机而不是苹果水果?为什么有的文档排在第一位?本文将从原理到源码,深度剖析 Lucene 的评分进化史:从经典的 TF-IDF 到现代的 BM25


1. 知识导图:Lucene 评分体系概览

在深入算法细节之前,我们先通过思维导图宏观了解 Lucene 的评分上下文。
Lucene Scoring
核心目标
找出最符合用户意图的文档
Ranking
基础理论
Boolean Model
VSM
经典算法 TF-IDF
词频
逆文档频率
协调因子
字段长度归一化
缺陷: 词频无限饱和
现代算法 BM25
Best Matching 25
ES 5.0+ 默认算法
k1
b


2. 传统霸主:TF-IDF 算法原理

在 Elasticsearch 5.0 之前,默认的评分算法基于 TF-IDF (Term Frequency - Inverse Document Frequency),并结合了向量空间模型(Vector Space Model, VSM)

2.1 核心公式拆解

Lucene 的经典 TF-IDF 评分公式并非简单的 T F × I D F TF \times IDF TF×IDF,而是经过了工程化改良:

s c o r e ( q , d ) = c o o r d ( q , d ) ⋅ q u e r y N o r m ( q ) ⋅ ∑ t ∈ q ( t f ( t ∈ d ) ⋅ i d f ( t ) 2 ⋅ t . g e t B o o s t ( ) ⋅ n o r m ( t , d ) ) score(q, d) = coord(q, d) \cdot queryNorm(q) \cdot \sum_{t \in q} ( tf(t \in d) \cdot idf(t)^2 \cdot t.getBoost() \cdot norm(t, d) ) score(q,d)=coord(q,d)⋅queryNorm(q)⋅t∈q∑(tf(t∈d)⋅idf(t)2⋅t.getBoost()⋅norm(t,d))

我们重点关注核心三要素:

  1. TF (Term Frequency) - 词频

    • 含义:检索词在文档中出现的次数越多,相关性越高。
    • Lucene 实现 : t f ( t ∈ d ) = f r e q u e n c y tf(t \in d) = \sqrt{frequency} tf(t∈d)=frequency
    • 直觉:一篇文章出现 5 次 "Elasticsearch" 比出现 1 次的更相关。
  2. IDF (Inverse Document Frequency) - 逆文档频率

    • 含义:检索词在所有文档中出现的越少(越稀有),权重越高。
    • Lucene 实现 : i d f ( t ) = 1 + log ⁡ ( d o c C o u n t d o c F r e q + 1 ) idf(t) = 1 + \log(\frac{docCount}{docFreq + 1}) idf(t)=1+log(docFreq+1docCount)
    • 直觉:"的"、"是" 这种词到处都有,权重极低;"Lucene" 这种专业词汇权重极高。
  3. Field Norm - 字段长度归一化

    • 含义:字段越短,匹配权值越高。
    • 直觉:在"标题"中匹配到关键词,通常比在长篇大论的"正文"中匹配到更重要。

2.2 TF-IDF 的致命缺陷

TF-IDF 最大的问题在于 TF 的线性(或平方根)增长

场景假设

  • 文档 A:出现 "AI" 这个词 1 次。
  • 文档 B:出现 "AI" 这个词 10 次。
  • 文档 C:出现 "AI" 这个词 100 次。

在 TF-IDF 看来,文档 C 的相关性会极高。但在人类认知中,一篇文章提到 10 次 "AI" 和 100 次 "AI" 可能都仅仅代表它是关于 AI 的文章,相关性并没有 10 倍的差距。这就是**"词频饱和度"**问题。


3. 现代标准:BM25 (Best Matching 25)

为了解决 TF-IDF 的缺陷,Okapi BM25 算法应运而生,并成为 Elasticsearch 5.x 之后的默认算法。BM25 基于概率相关模型(Probabilistic Relevance Model)。

3.1 BM25 vs TF-IDF 曲线对比

BM25 引入了**饱和(Saturation)**机制。当词频增加到一定程度时,分数的增长会趋于平缓。
词频对得分的影响 (TF-IDF vs BM25) 0 5 10 15 20 25 30 Term Frequency (词频) 10 9 8 7 6 5 4 3 2 1 0 Score (得分)

注:上图为示意图,展示了 TF-IDF 随词频持续增长,而 BM25 快速达到渐进极限。

3.2 BM25 核心公式

BM25 的公式看起来复杂,但本质是对 TF-IDF 的优化:

s c o r e ( D , Q ) = ∑ i = 1 n I D F ( q i ) ⋅ f ( q i , D ) ⋅ ( k 1 + 1 ) f ( q i , D ) + k 1 ⋅ ( 1 − b + b ⋅ ∣ D ∣ a v g d l ) score(D, Q) = \sum_{i=1}^{n} IDF(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot (1 - b + b \cdot \frac{|D|}{avgdl})} score(D,Q)=i=1∑nIDF(qi)⋅f(qi,D)+k1⋅(1−b+b⋅avgdl∣D∣)f(qi,D)⋅(k1+1)

3.3 关键参数详解 ( k 1 k_1 k1 与 b b b)

BM25 的强大之处在于它是可调优的。

参数 默认值 作用描述 图解说明
k 1 k_1 k1 1.2 控制词频饱和度 。 值越小,饱和越快(分数越早停止增长); 值越大,越接近 TF-IDF 的线性增长。 决定曲线弯曲的"快慢"。
b b b 0.75 控制字段长度归一化b=1: 完全归一化(短字段优势巨大)。 b=0: 禁用归一化(长短字段一视同仁)。 决定长文档是否被"惩罚"。
流程图:BM25 计算逻辑

输入: 查询词 q, 文档 D
计算 IDF
计算词频 f
计算文档长度 |D|
应用 k1 饱和度
应用 b 长度归一化
组合公式
最终得分


4 实战:如何在 Elasticsearch 中掌控评分

4.1 Explain API:调试神器

要理解为什么文档 A 排在文档 B 前面,必须使用 _explain API。

json 复制代码
GET /my_index/_explain/1
{
  "query": {
    "match": {
      "content": "elasticsearch"
    }
  }
}

返回结果解读:

  • value: 最终得分。
  • description : 描述计算过程,你会看到 idftfboost 等具体数值。
  • details : 递归展示每个部分的计算细节,比如 BM25 的 k 1 k_1 k1 和 b b b 实际应用情况。

4.2 自定义参数配置

如果你处理的是短文本 (如商品标题),可能希望 b b b 值大一些(完全归一化);如果你处理的是长篇技术文档 ,可能希望降低 b b b 的影响。

在 Mapping 中修改默认算法:

json 复制代码
PUT /my_custom_index
{
  "settings": {
    "index": {
      "similarity": {
        "my_bm25": {
          "type": "BM25",
          "k1": 1.5,
          "b": 0.6
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "similarity": "my_bm25"
      }
    }
  }
}

总结

特性 TF-IDF (Classic) BM25 (Modern)
词频增长 线性/平方根 (无上限) 渐进饱和 (更符合人类直觉)
长度归一化 简单倒数 可调参数 b b b 控制
参数调优 较少 k 1 , b k_1, b k1,b 灵活可调
适用场景 短文本、简单场景 通用场景,尤其是长短文本混合

Apache Lucene 通过从 TF-IDF 到 BM25 的演进,解决了长文档"作弊"和词频无限堆砌的问题。理解这些底层原理,不仅能帮助我们写出更好的 Query DSL,还能在遇到排序异常(Bad Ranking)时,迅速定位是 IDF 偏差、字段长度干扰还是词频饱和度设置不当。

相关推荐
峥嵘life4 小时前
Android EDLA CTS、GTS等各项测试命令汇总
android·学习·elasticsearch
invicinble5 小时前
一文了解git
大数据·git·elasticsearch
Elastic 中国社区官方博客6 小时前
使用 LangGraph 和 Elasticsearch 构建 人机协同( HITL )AI agent
大数据·人工智能·elasticsearch·搜索引擎·ai·机器人·全文检索
TracyCoder1237 小时前
ElasticSearch分布式架构(一):分片与路由的奥秘
分布式·elasticsearch·架构
TracyCoder1237 小时前
ElasticSearch分布式架构(二):集群一致性与共识——从Zen Discovery到Raft共识算法
分布式·elasticsearch·架构
码上上班7 小时前
一文学会apache httpd
apache
野生技术架构师7 小时前
Spring Boot 3 集成 Apache Calcite:多数据源查询的终极解决方案
spring boot·后端·apache
huohuopro7 小时前
git基本使用
大数据·git·elasticsearch
liux35287 小时前
Elasticsearch 8.13.2 单机部署与配置详细指南
大数据·elasticsearch·jenkins