【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

相关推荐
Elastic 中国社区官方博客4 小时前
使用 Elastic Cloud Serverless 扩展批量索引
大数据·运维·数据库·elasticsearch·搜索引擎·云原生·serverless
前端小L5 小时前
贪心算法专题(十):维度权衡的艺术——「根据身高重建队列」
javascript·算法·贪心算法
方得一笔5 小时前
自定义常用的字符串函数(strlen,strcpy,strcmp,strcat)
算法
Xの哲學5 小时前
Linux SMP 实现机制深度剖析
linux·服务器·网络·算法·边缘计算
Dxy12393102165 小时前
Elasticsearch 8.13.4 内存占用过大如何处理
大数据·elasticsearch·搜索引擎
wuk9986 小时前
使用PCA算法进行故障诊断的MATLAB仿真
算法·matlab
额呃呃6 小时前
二分查找细节理解
数据结构·算法
无尽的罚坐人生6 小时前
hot 100 283. 移动零
数据结构·算法·双指针
永远都不秃头的程序员(互关)6 小时前
C++动态数组实战:从手写到vector优化
c++·算法
水力魔方7 小时前
武理排水管网模拟分析系统应用专题5:模型克隆与并行计算
数据库·c++·算法·swmm