【Lucene】搜索引擎和文档相关性评分 BM25 算法的工作原理

BM25 算法的工作原理:


什么是 BM25 算法?

BM25 是一种流行的文本检索算法,广泛用于搜索引擎和文档相关性评分。它基于概率检索模型,旨在评估查询和文档之间的相关性。

核心公式

BM25 的公式如下:

score ( D , Q ) = ∑ t ∈ Q I D F ( t ) ⋅ f ( t , D ) ⋅ ( k 1 + 1 ) f ( t , D ) + k 1 ⋅ ( 1 − b + b ⋅ ∣ D ∣ avgdl ) \text{score}(D, Q) = \sum_{t \in Q} IDF(t) \cdot \frac{f(t, D) \cdot (k_1 + 1)}{f(t, D) + k_1 \cdot (1 - b + b \cdot \frac{|D|}{\text{avgdl}})} score(D,Q)=t∈Q∑IDF(t)⋅f(t,D)+k1⋅(1−b+b⋅avgdl∣D∣)f(t,D)⋅(k1+1)

  • I D F ( t ) IDF(t) IDF(t):词项 ( t ) 的逆文档频率。
  • f ( t , D ) f(t, D) f(t,D):词项 ( t ) 在文档 ( D ) 中的频率。
  • ∣ D ∣ |D| ∣D∣:文档 ( D ) 的长度。
  • avgdl \text{avgdl} avgdl:所有文档的平均长度。
  • k 1 k_1 k1:控制词项饱和度的参数,通常取 ( 1.2 )。
  • b b b:长度归一化参数,通常取 ( 0.75 )。
IDF 的计算

I D F ( t ) = log ⁡ N − n t + 0.5 n t + 0.5 + 1 IDF(t) = \log \frac{N - n_t + 0.5}{n_t + 0.5} + 1 IDF(t)=lognt+0.5N−nt+0.5+1

  • ( N ):文档总数。
  • ( n_t ):包含词 ( t ) 的文档数量。

代码实现

以下是 BM25 的简单 Python 实现:

python 复制代码
import math

class BM25:
    def __init__(self, documents, k1=1.2, b=0.75):
        self.documents = documents
        self.k1 = k1
        self.b = b
        self.doc_lengths = [len(doc) for doc in documents]
        self.avgdl = sum(self.doc_lengths) / len(self.doc_lengths)
        self.inverted_index = self._build_inverted_index()

    def _build_inverted_index(self):
        index = {}
        for i, doc in enumerate(self.documents):
            for word in set(doc):
                index.setdefault(word, []).append(i)
        return index

    def idf(self, term):
        n_t = len(self.inverted_index.get(term, []))
        return math.log((len(self.documents) - n_t + 0.5) / (n_t + 0.5) + 1)

    def score(self, query, doc_index):
        doc = self.documents[doc_index]
        score = 0
        for term in query:
            if term in doc:
                f = doc.count(term)
                idf = self.idf(term)
                score += idf * ((f * (self.k1 + 1)) / (f + self.k1 * (1 - self.b + self.b * len(doc) / self.avgdl)))
        return score

# 示例文档
documents = [
    ["hello", "world", "search", "engine"],
    ["hello", "search", "bm25", "algorithm"],
]
bm25 = BM25(documents)

# 查询得分
query = ["hello", "bm25"]
print(bm25.score(query, 0))  # 文档 0 的相关性得分
print(bm25.score(query, 1))  # 文档 1 的相关性得分

图示

  1. 词频与文档长度归一化

    • 用柱状图表示不同文档中词频和长度的对比,展示 BM25 如何平衡短文档和长文档。
  2. IDF 权重

    • 用折线图展示常见词和稀有词的 IDF 值,突出稀有词对相关性的重要贡献。

为细化 BM25 相关图表,以下是具体建议和生成方式:


图表 1: 词频与文档长度归一化

目标:展示 BM25 如何平衡短文档和长文档的评分。

  • 图类型:条形图。
  • 数据结构:每个文档的总词频与长度。
  • 关键点 :对比文档长度对评分的影响。

示例生成代码(使用 Matplotlib):

python 复制代码
import matplotlib.pyplot as plt

# 示例文档数据
doc_lengths = [4, 4, 6, 10]  # 文档长度
term_frequencies = [2, 3, 4, 5]  # 查询词的频率

# 绘图
plt.bar(range(len(doc_lengths)), doc_lengths, label="Document Lengths", alpha=0.6)
plt.bar(range(len(term_frequencies)), term_frequencies, label="Term Frequencies", alpha=0.6)
plt.xlabel("Documents")
plt.ylabel("Values")
plt.legend()
plt.title("Term Frequency vs Document Length")
plt.show()

图表 2: 逆文档频率 (IDF) 权重

目标:展示 IDF 在常见词与稀有词上的差异。

  • 图类型:折线图。
  • 数据结构:不同词项的文档频率与其对应的 IDF。
  • 关键点 :稀有词拥有更高权重,帮助区分相关性。

示例生成代码:

python 复制代码
import numpy as np

# 示例词项数据
doc_count = 100  # 总文档数
term_doc_freq = np.array([1, 5, 20, 50, 90])  # 包含查询词的文档数
idf_values = np.log((doc_count - term_doc_freq + 0.5) / (term_doc_freq + 0.5) + 1)

# 绘图
plt.plot(term_doc_freq, idf_values, marker='o')
plt.xlabel("Term Document Frequency")
plt.ylabel("IDF Value")
plt.title("IDF Curve")
plt.grid()
plt.show()

图表 3: BM25 综合评分变化

目标:展示 BM25 参数 (k_1) 和 (b) 的调整对评分的影响。

  • 图类型:3D 表面图或热图。
  • 数据结构:BM25 分数在不同 (k_1) 和 (b) 参数组合下的变化。
  • 关键点:参数对相关性评分的微调作用。

示例生成代码:

python 复制代码
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

# 参数网格
k1 = np.linspace(0.5, 2.0, 50)
b = np.linspace(0.0, 1.0, 50)
k1, b = np.meshgrid(k1, b)
scores = (k1 + 1) / (k1 * (1 - b + b * 0.5) + 1)

# 绘制 3D 图
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(k1, b, scores, cmap='viridis')
ax.set_xlabel("k1")
ax.set_ylabel("b")
ax.set_zlabel("Score")
ax.set_title("BM25 Scoring Surface")
plt.show()

以上图表可以帮助直观理解 BM25 的重要概念。

ref:https://emschwartz.me/understanding-the-bm25-full-text-search-algorithm/?continueFlag=1f3c7fda32b1a504d3118d71fe55ae8f

相关推荐
A懿轩A26 分钟前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
古希腊掌管学习的神27 分钟前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人30 分钟前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
半盏茶香31 分钟前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
忘梓.1 小时前
解锁动态规划的奥秘:从零到精通的创新思维解析(3)
算法·动态规划
tinker在coding4 小时前
Coding Caprice - Linked-List 1
算法·leetcode
XH华8 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生8 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_8 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子9 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘