Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

这篇具有很好参考价值的文章主要介绍了Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

这是第一部分 “Elasticsearch:实用 BM25 - 第 1 部分:分片如何影响 Elasticsearch 中的相关性评分” 的续篇。

BM25算法

我将尽可能深入这里的数学以解释正在发生的事情,但这是我们查看 BM25 公式的结构以深入了解正在发生的事情的部分。 首先我们来看看公式,然后我将把每个组件分解成可以理解的部分:

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

我们可以看到一些常见的组件,如 qi、IDF(qi)、f(qi,D)、k1、b,以及一些关于字段长度的内容。 这是每一个的全部内容:

1)qi 是第 i 个查询词。

例如,如果我搜索 “shane”,只有 1 个查询词,所以 q0 是 “shane”。 如果我用英文搜索 “shane connelly”,Elasticsearch 会看到空格并将其标记为 2 个术语:q0 将是 “shane”,q1 将是 connelly”。 这些查询项被插入等式的其他位,所有的都被加起来。

2)IDF(qi) 是第 i 个查询词的逆文档频率( inverse document frequency)。

对于以前使用过 TF/IDF 的人来说,IDF 的概念对你来说可能很熟悉。 如果没有,不用担心! (如果是这样,请注意 TF/IDF 中的 IDF 公式与 BM25 中的 IDF 之间存在差异。)我们公式的 IDF 组件衡量一个术语在所有文档中出现的频率并 “惩罚” 常见的术语。 这部分 Lucene/BM25 使用的实际公式是:

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

其中 docCount 是分片中具有该字段值的文档总数(跨分片,如果你使用 search_type=dfs_query_then_fetch),f(qi) 是包含第 i 个查询词的文档数。 我们可以在示例中看到 “shane” 出现在所有 4 个文档中,因此对于术语 “shane”,我们最终得到一个 IDF(“shane”):

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

然而,我们可以看到 “connelly” 只出现在 2 个文档中,所以我们得到一个 IDF(“connelly”):

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

我们可以在这里看到包含这些较稀有术语的查询(“connelly” 在我们的 4 文档语料库中比 “shane” 更稀有)具有更高的乘数,因此它们对最终分数的贡献更大。 这符合直觉:术语 “the” 可能出现在几乎所有英文文档中,因此当用户搜索 “the elephant” 之类的内容时,“elephant” 可能更重要 —— 我们希望它对 分数 —— 而不是术语 “the”(几乎所有文档中都会出现)。 

3)我们看到分母中字段的长度除以平均字段长度为 fieldLen/avgFieldLen

我们可以将其视为文档相对于平均文档长度的长度。 如果文档长于平均值,则分母变大(分数降低),如果文档短于平均值,则分母变小(分数增加)。 请注意,Elasticsearch 中字段长度的实现是基于术语的数量(相对于字符长度等其他因素)。 这与原始 BM25 论文中的描述完全相同,但如果你愿意,我们确实有一个特殊标志 (discount_overlaps) 来专门处理同义词。 考虑这一点的方法是,文档中的术语越多 —— 至少是与查询不匹配的术语 —— 文档的分数越低。 同样,这具有直觉意义:如果一份文档有 300 页长,并且只提到了我的名字一次,那么它与我的关系就不太可能像一条提到我一次的短推文那样与我有关。

4)我们看到一个变量 b 出现在分母中,它乘以我们刚刚讨论的字段长度的比率。 如果 b 越大,文档长度与平均长度相比的影响就越大。 看到这一点,你可以想象如果将 b 设置为 0,则长度比率的影响将完全无效,文档的长度将不会影响分数。 默认情况下,b 在 Elasticsearch 中的值为 0.75。

5)最后,我们看到分数的两个组成部分同时出现在分子和分母中:k1 和 f(qi,D)。 它们在两侧的出现让人很难仅通过公式了解它们的作用,但让我们快速进入。

  • f(qi,D) 是 “文档 D 中第 i 个查询词出现了多少次?” 在所有这些文档中,f(“shane”, D) 为 1,但 f(“connelly”, D) 有所不同:文档 3 和 4 为 1,文档 1 和 2 为 0。如果有第 5 个 有文本 “shane shane” 的文档,它的 f(“shane”,D) 为 2。我们可以看到 f(qi, D) 在分子和分母中,还有那个特殊的“ k1” 我们接下来要讨论的因素。 考虑 f(qi,D) 的方式是查询词在文档中出现的次数越多,它的分数就越高。 这在直觉上是有道理的:一份多次出现我们名字的文档比只出现一次的文档更有可能与我们相关。
  • k1 是帮助确定术语频率饱和特性的变量。 也就是说,它限制了单个查询词对给定文档分数的影响程度。 它通过接近渐近线来做到这一点。 你可以在这里看到 BM25 与 TF/IDF 的比较:

Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量

更高/更低的 k1 值意味着 “BM25 的 tf()” 曲线的斜率发生变化。 这具有改变 “术语出现额外次数增加额外分数” 的方式的效果。 对 k1 的解释是,对于平均长度的文档,术语频率的值给出的分数是所考虑术语的最大分数的一半。 tf 对分数的影响曲线在 tf() ≤ k1 时增长很快,而在 tf() > k1 时越来越慢。

继续我们的示例,对于 k1,我们控制了“向文档添加第二个 ‘shane’ 对得分的贡献比第一个或第三个与第二个相比多多少?”这个问题的答案。 较高的 k1 意味着对于该术语的更多实例,每个术语的分数可以继续上升相对更多。 k1 的值为 0 意味着除 IDF(qi) 之外的所有内容都将抵消。 默认情况下,k1 在 Elasticsearch 中的值为 1.2。

用我们的新知识重新审视我们的搜索

我们将删除我们的人员索引并仅使用 1 个分片重新创建它,这样我们就不必使用 search_type=dfs_query_then_fetch。 我们将通过设置三个索引来测试我们的知识:一个 k1 的值为 0,b 为 0.5,第二个索引 (people2) 的值为 b 为 0,k1 为 10,第三个索引 (people3) b 的值为 1,k1 为 5。

DELETE people
PUT people
{
  "settings": {
    "number_of_shards": 1,
    "index" : {
        "similarity" : {
          "default" : {
            "type" : "BM25",
            "b": 0.5,
            "k1": 0
          }
        }
    }
  }
}
PUT people2
{
  "settings": {
    "number_of_shards": 1,
    "index" : {
        "similarity" : {
          "default" : {
            "type" : "BM25",
            "b": 0,
            "k1": 10
          }
        }
    }
  }
}
PUT people3
{
  "settings": {
    "number_of_shards": 1,
    "index" : {
        "similarity" : {
          "default" : {
            "type" : "BM25",
            "b": 1,
            "k1": 5
          }
        }
    }
  }
}

现在我们将向所有三个索引添加一些文档:

POST people/_doc/_bulk
{ "index": { "_id": "1" } }
{ "title": "Shane" }
{ "index": { "_id": "2" } }
{ "title": "Shane C" }
{ "index": { "_id": "3" } }
{ "title": "Shane P Connelly" }
{ "index": { "_id": "4" } }
{ "title": "Shane Connelly" }
{ "index": { "_id": "5" } }
{ "title": "Shane Shane Connelly Connelly" }
{ "index": { "_id": "6" } }
{ "title": "Shane Shane Shane Connelly Connelly Connelly" }

POST people2/_doc/_bulk
{ "index": { "_id": "1" } }
{ "title": "Shane" }
{ "index": { "_id": "2" } }
{ "title": "Shane C" }
{ "index": { "_id": "3" } }
{ "title": "Shane P Connelly" }
{ "index": { "_id": "4" } }
{ "title": "Shane Connelly" }
{ "index": { "_id": "5" } }
{ "title": "Shane Shane Connelly Connelly" }
{ "index": { "_id": "6" } }
{ "title": "Shane Shane Shane Connelly Connelly Connelly" }

POST people3/_doc/_bulk
{ "index": { "_id": "1" } }
{ "title": "Shane" }
{ "index": { "_id": "2" } }
{ "title": "Shane C" }
{ "index": { "_id": "3" } }
{ "title": "Shane P Connelly" }
{ "index": { "_id": "4" } }
{ "title": "Shane Connelly" }
{ "index": { "_id": "5" } }
{ "title": "Shane Shane Connelly Connelly" }
{ "index": { "_id": "6" } }
{ "title": "Shane Shane Shane Connelly Connelly Connelly" }

现在,当我们这样做时:

GET /people/_search
{
  "query": {
    "match": {
      "title": "shane"
    }
  }
}

我们可以在 people 中看到所有文档的分数都是 0.074107975。 这符合我们对将 k1 设置为 0 的理解:只有搜索词的 IDF 对分数有影响!

现在让我们检查 people2,它有 b = 0 和 k1 = 10:

GET /people2/_search
{
  "query": {
    "match": {
      "title": "shane"
    }
  }
}

从这次搜索的结果中可以看出两点。

首先,我们可以看到分数完全按照 “shane” 出现的次数排序。 文档 1、2、3 和 4 都有一次 “shane”,因此共享相同的分数 0.074107975。 文档 5 有两次“shane”,因此由于 f(“shane”, D5) = 2 而获得更高的分数 (0.13586462),由于 f(“shane”, D6) = 3,文档 6 再次获得更高的分数 (0.18812023)。这符合我们将 people2 中的 b 设置为 0 的直觉:长度 —— 或文档中术语的总数 —— 不影响评分; 只有匹配项的计数和相关性。

第二点要注意的是,这些分数之间的差异是非线性的,尽管这 6 个文档看起来确实非常接近线性。

  • 没有出现我们的搜索词和第一次出现之间的分数差异是 0.074107975
  • 添加我们的搜索词的第二次出现和第一次出现之间的分数差异是 0.13586462 - 0.074107975 = 0.061756645
  • 添加我们的搜索词的第三次出现和第二次出现之间的分数差异是 0.18812023 - 0.13586462 = 0.05225561

0.074107975 非常接近 0.061756645,而 0.061756645 非常接近 0.05225561,但它们明显在下降。 这看起来几乎是线性的原因是因为 k1 很大。 我们至少可以看到分数并没有随着出现次数的增加而线性增加 —— 如果是的话,我们希望看到每个额外的词项都有相同的差异。 我们将在查看 people3 后回到这个想法。

现在让我们检查 people3,它有 k1 = 5 和 b = 1:

GET /people3/_search
{
  "query": {
    "match": {
      "title": "shane"
    }
  }
}

我们得到以下命中:

"hits": [
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "1",
        "_score": 0.16674294,
        "_source": {
          "title": "Shane"
        }
      },
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "6",
        "_score": 0.10261105,
        "_source": {
          "title": "Shane Shane Shane Connelly Connelly Connelly"
        }
      },
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.102611035,
        "_source": {
          "title": "Shane C"
        }
      },
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "4",
        "_score": 0.102611035,
        "_source": {
          "title": "Shane Connelly"
        }
      },
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "5",
        "_score": 0.102611035,
        "_source": {
          "title": "Shane Shane Connelly Connelly"
        }
      },
      {
        "_index": "people3",
        "_type": "_doc",
        "_id": "3",
        "_score": 0.074107975,
        "_source": {
          "title": "Shane P Connelly"
        }
      }
    ]

我们可以在 people3 中看到,现在匹配项(“shane”)与不匹配项的比率是唯一影响相对得分的因素。 因此,像文档 3 这样的文档,在低于文档 2、4、5 和 6 的 3 个得分中只有 1 个词匹配,它们都恰好匹配了一半的词,而那些得分都低于与文档 1 完全匹配的文档。

同样,我们可以注意到 people2 和 people3 中得分最高的文档和得分较低的文档之间存在 “巨大” 差异。 这(再次)归功于 k1 的较大值。 作为额外的练习,尝试删除 people2/people3 并将它们重新设置为 k1 = 0.01 之类的值,您会发现具有较少文档之间的分数更小。 当 b = 0 且 k1 = 0.01 时:

  • 没有出现我们的搜索词和第一次出现之间的分数差异是 0.074107975
  • 添加我们的搜索词的第二次出现和第一次出现之间的分数差异是 0.074476674 - 0.074107975 = 0.000368699
  • 添加我们的搜索词的第三次出现和第二次出现之间的分数差异是 0.07460038 - 0.074476674 = 0.000123706

因此,当 k1 = 0.01 时,我们可以看到每次额外出现的分数影响比 k1 = 5 或 k1 = 10 时下降得更快。第 4 次出现对分数的影响比第 3 次增加的少得多,依此类推。 换句话说,这些较小的 k1 值会使术语得分更快地饱和。 正如我们所料!

希望这有助于了解这些参数对各种文档集的作用。 有了这些知识,接下来我们将跳转到如何选择合适的 b 和 k1 以及 Elasticsearch 如何提供工具来理解分数和迭代你的方法。文章来源地址https://www.toymoban.com/news/detail-487281.html

到了这里,关于Elasticsearch:实用 BM25 - 第 2 部分:BM25 算法及其变量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch:结合两全其美:Elasticsearch 与 BM25 和 HNSW 的混合搜索

    就搜索算法而言,没有万能的解决方案。 不同的算法在不同的场景下效果更好,有时需要算法的组合才能达到最好的效果。 在 Elasticsearch 中,一种流行的组合搜索算法的方法是使用混合搜索,将用于文本搜索的 BM25 算法与用于最近邻搜索的 HNSW 算法相结合。 在这篇博文中,

    2024年02月06日
    浏览(34)
  • 使用ElasticSearch完成大模型+本地知识库:BM25+Embedding模型+Learned Sparse Encoder 新特性

    本文指出,将BM25,向量检索Embedding模型后近似KNN相结合,可以让搜索引擎既能理解用户查询的字面意义,又能捕捉到查询的深层次语义,从而提供更全面、更精确的搜索结果。这种混合方法在现代搜索引擎中越来越普遍,因为它结合了传统搜索的精确性和基于AI的搜索的语义

    2024年02月03日
    浏览(68)
  • 集成多元算法,打造高效字面文本相似度计算与匹配搜索解决方案,助力文本匹配冷启动[BM25、词向量、SimHash、Tfidf、SequenceMatcher]

    搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目

    2024年02月05日
    浏览(72)
  • Python篇——数据结构与算法(第四部分:希尔排序及其讨论、计数排序、桶排序、基数排序)

    希尔排序(shell sort)是一种分组插入排序算法 首先取一个整数d1=n/2,将元素分为d1个组,每组相邻两元素之间距离为d1,在各 组内 进行直接插入排序 取第二个整数d2=d1/2,重复上述分组排序过程,知道di=1,即所有元素在同一组内进行直接插入排序。 希尔排序每趟并不使某些

    2024年02月07日
    浏览(42)
  • Elasticsearch:介绍 kNN query,这是进行 kNN 搜索的专家方法

    作者:来自 Elastic Mayya Sharipova, Benjamin Trent Elasticsearch 中的 kNN 搜索被组织为搜索请求的顶层(top level)部分。 我们这样设计是为了: 无论分片数量多少,它总是可以返回全局 k 个最近邻居 这些全局 k 个结果与其他查询的结果相结合以形成混合搜索 全局 k 结果被传递到聚合

    2024年01月23日
    浏览(42)
  • 关于图像去噪的BM3D算法python库讲解

    目录 基本原理 一、BM3D算法的详解 ​编辑 二、python中的应用 总结 图像做块间匹配,把多张相似的2D图像块组成3D组,对3D组进行域变换,利用域变换上系数的稀疏性,进行滤波,然再逆向3D域变换,得到滤波后的图像块,放回原来的位置,每个像素可能得到多次滤波的结果,

    2024年02月16日
    浏览(42)
  • 23.7.25 杭电暑期多校3部分题解

    题目大意 你有一个长度为 n n n 的序列,你每次可以向一个栈内放一个数,如果栈不为空并且栈顶的数大于你放的数,那么你放的数会变成栈顶的数再放入,问当栈的大小为 1 1 1 到 n n n 时分别有几种情况 解题思路 考虑dp, f i , j f_{i,j} f i , j ​ 表示放了 i i i 个数,最大的数

    2024年02月15日
    浏览(37)
  • Android----GitHub上25个超炫酷又实用的开源UI框架,强烈建议收藏!

    分类侧滑菜单,Yalantis 出品。 项目地址:https://github.com/Yalantis/Side-Menu.Android 2.Context-Menu.Android 可以方便快速集成漂亮带有动画效果的上下文菜单,Yalantis出品。 项目地址:https://github.com/Yalantis/Context-Menu.Android 3.Pull-to-Refresh.Rentals-Android 提供一个简单可以自定义的下拉刷新实现

    2024年03月23日
    浏览(409)
  • GCP 上的人工智能实用指南:第三、四部分

    原文:Hands-On Artificial Intelligence on Google Cloud Platform 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只关心如何实现目标。——《原则》,生活原则 2.3.c 张量处理单元 ( TPU )是 Goog

    2023年04月19日
    浏览(94)
  • 关于时空数据的培训 GAN:实用指南(第 01/3 部分)

            GAN 是迄今为止最受欢迎的深度生成模型,主要是因为它们最近在图像生成任务上产生了令人难以置信的结果。然而,GAN并不容易训练,因为它们的基本设计引入了无数的不稳定性。如果你尝试过用MNIST以外的任何东西训练GAN,你很快就会意识到,所有关于训练他们

    2024年02月07日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包