Elasticsearch:倒数排序融合 - Reciprocal rank fusion (RRF)

注意:RRF 在 Elastic Stack 8.8 中正式提供。

倒数排序融合(RRF)是一种将具有不同相关性指标的多个结果集组合成单个结果集的方法。 RRF 无需调优,不同的相关性指标也不必相互关联即可获得高质量的结果。该方法的优势在于不利用相关分数,而仅靠排名计算。相关分数存在的问题在于不同模型的分数范围差。

使用 Reciprocal Rank Fusion (RRF) 的简化混合搜索

通常,最好的排名是通过组合多种排名方法来实现的,例如 BM25 和生成密集向量嵌入的 ML 模型。 在实践中,将结果集组合成一个单一的组合相关性排名结果集被证明是非常具有挑战性的。 当然,理论上你可以将每个结果集的分数归一化(因为原始分数在完全不同的范围内),然后进行线性组合,根据每个排名的分数加权和排序最终结果集方法。 只要你提供正确的权重,Elasticsearch 就支持它并且运行良好。 为此,你需要了解环境中每种方法得分的统计分布,并有条不紊地优化权重。 实际上,这超出了绝大多数用户的能力。

另一种方法是 RRF 算法,它提供了出色的排序方法零样本混合,正如学术研究所证明的那样。 如果你不了解不同方法中排名分数的确切分布,这不仅是最好的混合方式,而且客观上也是混合排名方法的好方法 —— 即使你知道如何归一化及分数的分布情况,也很难被击败。 基本概念是结果的组合顺序由每个结果集中每个文档的位置(和存在)定义。 因此可以方便地忽略排名分数。

Elastic 8.8 支持具有多个密集向量查询和在倒排索引上运行的单个查询的 RRF。 在不久的将来,我们希望支持来自 BM25 和 Elastic 的检索模型(两者都是稀疏向量)的混合结果,从而产生同类最佳的零样本集(无域内训练)排名方法。

  • D - 文档集
  • R - 一组排名作为 1..|D| 的排列
  • K - 通常默认设置为 60

RRF 使用以下公式来确定对每个文档进行排名的分数:

score = 0.0
for q in queries:
    if d in result(q):
        score += 1.0 / ( k + rank( result(q), d ) )
return score

# where
# k is a ranking constant
# q is a query in the set of queries
# d is a document in the result set of q
# result(q) is the result set of q
# rank( result(q), d ) is d's rank within the result(q) starting from 1

倒数排序融合 API

你可以将 RRF 用作搜索的一部分,以使用来自:

  • 1 个查询(query)和 1 个或多个 kNN 搜索
  • 2 个或更多 kNN 搜索

rrf 参数是一个可选对象,定义为搜索请求 rank parameter 的一部分。 rrf 对象包含以下参数:

条目描述
rank_constant(可选,整数)此值确定每个查询的单个结果集中的文档对最终排名结果集的影响程度。 较高的值表示排名较低的文档具有更大的影响力。 此值必须大于或等于 1。默认为 60。
window_size(可选,整数)此值确定每个查询的单个结果集的大小。 较高的值将以性能为代价提高结果相关性。 最终排名的结果集被修剪为搜索请求的 <<search-size-param, size>。 window_size 必须大于或等于 size 且大于或等于 1。默认为 100。

使用 RRF 的示例请求:

GET example-index/_search
{
    "query": {
        "term": {
            "text": "shoes"
        }
    },
    "knn": {
        "field": "vector",
        "query_vector": [1.25, 2, 3.5],
        "k": 50,
        "num_candidates": 100
    },
    "rank": {
        "rrf": {
            "window_size": 50,
            "rank_constant": 20
        }
    }
}

在上面的示例中,我们首先执行 kNN 搜索以获取其全球前 50 名的结果。 然后我们执行查询以获取其全球前 50 名的结果。 之后,在一个协调节点上,我们将 knn 搜索结果与查询结果结合起来,根据 RRF 方法对它们进行排序,得到最终的 top 10 结果。

请注意,如果来自 knn 搜索的 k 大于 window_size,则结果将被截断为 window_size。 如果 k 小于 window_size,则结果为 k 大小。

倒数排序融合支持的功能

RRF 确实支持:

  • from
  • aggregations

RRF 目前不支持:

  • scroll
  • point in time
  • sort
  • rescore
  • suggesters
  • highlighting
  • collapse
  • explain
  • profiling

使用不支持的功能作为使用 RRF 的搜索的一部分将导致异常。

倒数排序融合完整示例

我们首先为具有文本字段、向量字段和整数字段的索引创建映射,同时索引多个文档。 对于这个例子,我们将使用一个只有一个维度的向量来使排名更容易解释。

PUT example-index
{
  "mappings": {
    "properties": {
      "text": {
        "type": "text"
      },
      "vector": {
        "type": "dense_vector",
        "dims": 1,
        "index": true,
        "similarity": "l2_norm"
      },
      "integer": {
        "type": "integer"
      }
    }
  }
}

PUT example-index/_doc/1
{
    "text" : "rrf",
    "vector" : [5],
    "integer": 1
}

PUT example-index/_doc/2
{
    "text" : "rrf rrf",
    "vector" : [4],
    "integer": 2
}

PUT example-index/_doc/3
{
    "text" : "rrf rrf rrf",
    "vector" : [3],
    "integer": 1
}

PUT example-index/_doc/4
{
    "text" : "rrf rrf rrf rrf",
    "integer": 2
}

PUT example-index/_doc/5
{
    "vector" : [0],
    "integer": 1
}

POST example-index/_refresh

现在,我们使用带有查询、kNN 搜索和术语聚合的 RRF 执行搜索。

GET example-index/_search
{
  "query": {
    "term": {
      "text": "rrf"
    }
  },
  "knn": {
    "field": "vector",
    "query_vector": [
      3
    ],
    "k": 5,
    "num_candidates": 5
  },
  "rank": {
    "rrf": {
      "window_size": 5,
      "rank_constant": 1
    }
  },
  "size": 3,
  "aggs": {
    "int_count": {
      "terms": {
        "field": "integer"
      }
    }
  }
}

我们收到带有排名 hits 和术语聚合结果的响应。 请注意,_score 为 null,我们改为使用 _rank 来显示排名靠前的文档。

{
  "took": 16,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 5,
      "relation": "eq"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "example-index",
        "_id": "3",
        "_score": null,
        "_rank": 1,
        "_source": {
          "text": "rrf rrf rrf",
          "vector": [
            3
          ],
          "integer": 1
        }
      },
      {
        "_index": "example-index",
        "_id": "2",
        "_score": null,
        "_rank": 2,
        "_source": {
          "text": "rrf rrf",
          "vector": [
            4
          ],
          "integer": 2
        }
      },
      {
        "_index": "example-index",
        "_id": "4",
        "_score": null,
        "_rank": 3,
        "_source": {
          "text": "rrf rrf rrf rrf",
          "integer": 2
        }
      }
    ]
  },
  "aggregations": {
    "int_count": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 1,
          "doc_count": 3
        },
        {
          "key": 2,
          "doc_count": 2
        }
      ]
    }
  }
}

让我们分解一下这些点击率是如何排名的。 我们首先分别运行查询和 kNN 搜索,以收集它们各自的命中率。

首先,我们查看查询的 hits。

GET example-index/_search?filter_path=**.hits
{
  "query": {
    "term": {
      "text": "rrf"
    }
  }
}

上面的命令显示的结果为:

{
  "hits": {
    "hits": [
      {
        "_index": "example-index",
        "_id": "4",
        "_score": 0.16152832,         [1]
        "_source": {
          "text": "rrf rrf rrf rrf",
          "integer": 2
        }
      },
      {
        "_index": "example-index",
        "_id": "3",
        "_score": 0.15876243,         [2]
        "_source": {
          "text": "rrf rrf rrf",
          "vector": [
            3
          ],
          "integer": 1
        }
      },
      {
        "_index": "example-index",
        "_id": "2",
        "_score": 0.15350538,         [3]
        "_source": {
          "text": "rrf rrf",
          "vector": [
            4
          ],
          "integer": 2
        }
      },
      {
        "_index": "example-index",
        "_id": "1",
        "_score": 0.13963442,         [4]
        "_source": {
          "text": "rrf",
          "vector": [
            5
          ],
          "integer": 1
        }
      }
    ]
  }
}
  • [1]  rank 1, _id 4
  • [2]  rank 2, _id 3
  • [3]  rank 3, _id 2
  • [4]  rank 4, _id 1

请注意,我们的第一个命中没有 vector 字段的值。 现在,我们查看 kNN 搜索的结果。

GET example-index/_search?filter_path=**.hits
{
  "knn": {
    "field": "vector",
    "query_vector": [
      3
    ],
    "k": 5,
    "num_candidates": 5
  }
}

上面搜索的结果为:

{
  "hits": {
    "hits": [
      {
        "_index": "example-index",
        "_id": "3",                      [1]
        "_score": 1,
        "_source": {
          "text": "rrf rrf rrf",
          "vector": [
            3
          ],
          "integer": 1
        }
      },
      {
        "_index": "example-index",
        "_id": "2",                     [2]
        "_score": 0.5,
        "_source": {
          "text": "rrf rrf",
          "vector": [
            4
          ],
          "integer": 2
        }
      },
      {
        "_index": "example-index",
        "_id": "1",                     [3]
        "_score": 0.2,
        "_source": {
          "text": "rrf",
          "vector": [
            5
          ],
          "integer": 1
        }
      },
      {
        "_index": "example-index",
        "_id": "5",                     [4]
        "_score": 0.1,
        "_source": {
          "vector": [
            0
          ],
          "integer": 1
        }
      }
    ]
  }
}
  • [1]  rank 1, _id 3
  • [2]  rank 2, _id 2
  • [3]  rank 3, _id 1
  • [4]  rank 4, _id 5

我们现在可以获取两个单独排名的结果集并将 RRF 公式应用于它们以获得我们的最终排名。

# doc  | query     | knn       | score
_id: 1 = 1.0/(1+4) + 1.0/(1+3) = 0.4500
_id: 2 = 1.0/(1+3) + 1.0/(1+2) = 0.5833
_id: 3 = 1.0/(1+2) + 1.0/(1+1) = 0.8333
_id: 4 = 1.0/(1+1)             = 0.5000
_id: 5 =             1.0/(1+4) = 0.2000

我们根据 RRF 公式对文档进行排名,其中 window_size 为 5,截断 RRF 结果集中底部的 2 个文档,大小为 3。我们以 _id: 3 作为 _rank: 1, _id: 2 作为 _rank: 2, 及 _id: 4 作为 _rank: 3。这个排名符合预期的原始 RRF 搜索的结果集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/386116.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VBA技术资料MF118:在多个工作表中插入页眉和页脚

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

如何在PDF 文件中删除页面?

查看不同的工具以及解释如何在 Windows、Android、macOS 和 iOS 上从 PDF 删除页面的步骤&#xff1a; PDF 是最难处理的文件格式之一。曾经有一段时间&#xff0c;除了阅读之外&#xff0c;无法用 PDF 做任何事情。但是今天&#xff0c;有许多应用程序和工具可以让您用它们做…

片上网络NoC(3)——拓扑指标

目录 一、概述 二、指标 2.1 与网络流量无关的指标 2.1.1 度&#xff08;degree&#xff09; 2.1.2 对分带宽&#xff08;bisection bandwidth&#xff09; 2.1.3 网络直径&#xff08;diameter&#xff09; 2.2 与网络流量相关的指标 2.2.1 跳数&#xff08;hop coun…

【复现】Supabase后端服务 SQL注入漏洞_48

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 Supabase是什么 Supabase将自己定位为Firebase的开源替代品&#xff0c;提供了一套工具来帮助开发者构建web或移动应用程序。 Sup…

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等&#xff0c;自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领…

车载诊断协议DoIP系列 —— OSI模型DoIP参考

车载诊断协议DoIP系列 —— OSI模型DoIP参考 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再…

Vue源码系列讲解——模板编译篇【三】(HTML解析器)

目录 1. 前言 2. HTML解析器内部运行流程 3. 如何解析不同的内容 3.1 解析HTML注释 3.2 解析条件注释 3.3 解析DOCTYPE 3.4 解析开始标签 3.5 解析结束标签 3.6 解析文本 4. 如何保证AST节点层级关系 5. 回归源码 5.1 HTML解析器源码 5.2 parseEndTag函数源码 6. …

使用MICE进行缺失值的填充处理

在我们进行机器学习时&#xff0c;处理缺失数据是非常重要的&#xff0c;因为缺失数据可能会导致分析结果不准确&#xff0c;严重时甚至可能产生偏差。处理缺失数据是保证数据分析准确性和可靠性的重要步骤&#xff0c;有助于确保分析结果的可信度和可解释性。 在本文中&#…

Linux_环境变量_命令行参数

一.环境变量 在Linux中自己写的程序必须要带路径才能运行&#xff0c;相对路径或是绝对路径&#xff0c;但是像ls pwd这样的程序&#xff0c;不带路径也能运行。当你想要运行一个程序时&#xff1a; 如果带有路径的话&#xff0c;则直接将对应路径的程序加载进内存&#xff0…

LeetCode、1268. 搜索推荐系统【中等,前缀树+优先队列、排序+前缀匹配】

文章目录 前言LeetCode、1268. 搜索推荐系统【中等&#xff0c;前缀树优先队列、排序前缀匹配】题目类型及分类思路API调用&#xff08;排序前缀匹配&#xff09;前缀树优先队列 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创…

内网穿透 | 推荐两个免费的内网穿透工具

目录 1、简介 2、Ngrok 2.1、下载安装 2.2、运行 2.3、固定域名 2.4、配置多服务 3、cpolar 3.1、下载安装 3.2、运行 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应…

2024 年 5 款适用于免费 iPhone 数据恢复的工具软件

搜索一下&#xff0c;你会发现许多付费或免费的iPhone数据恢复工具声称它们可以帮助你以很高的成功率找回所有丢失的数据。然而&#xff0c;这正是问题所在。真的很难做出选择。为了进一步帮助您解决数据丢失问题&#xff0c;我们在此列出了 5 款最好的免费 iPhone 恢复软件供您…

[Doris] Doris的安装和部署 (二)

文章目录 1.安装要求1.1 Linux操作系统要求1.2 软件需求1.3 注意事项1.4 内部端口 2.集群部署2.1 操作系统安装要求2.2 下载安装包2.3 解压2.4 配置FE2.5 配置BE2.6 添加BE2.7 FE 扩容和缩容2.8 Doris 集群群起脚本 3.图形化 1.安装要求 1.1 Linux操作系统要求 1.2 软件需求 1…

Hive的小文件问题

目录 一、小文件产生的原因 二、小文件的危害 三、小文件的解决方案 3.1 小文件的预防 3.1.1 减少Map数量 3.1.2 减少Reduce的数量 3.2 已存在的小文件合并 3.2.1 方式一&#xff1a;insert overwrite (推荐) 3.2.2 方式二&#xff1a;concatenate 3.2.3 方式三&#xff…

[Python] 如何用import导入模块

本篇博客来记以下关于import导入模块的笔记~ 可莉将这篇博客收录在了&#xff1a;《Python》 可莉推荐的优质博主主页&#xff1a;Kevin ’ s blog 我们在Python中可以使用import从标准库中导入一天模块&#xff0c;模块相当于是一个 .py 文件&#xff0c;我们导入后调用相当于…

腾讯云4核8G服务器多少钱?646元一年零3个月

腾讯云服务器4核8G配置优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云百科txybk.com分…

pythondjangomysql苏州一日游之可视化分析69216-计算机毕业设计项目选题推荐(附源码)

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对旅游服务等问题&#xff0c;对旅游服务进行…

【动态规划】【中位数】【C++算法】1478. 安排邮筒

# 作者推荐 【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目 本文涉及知识点 动态规划汇总 LeetCode1478. 安排邮筒 给你一个房屋数组houses 和一个整数 k &#xff0c;其中 houses[i] 是第 i 栋房子在一条街上的位置&#xff0c;现需要在这条街上安排 k…

C++基础入门:掌握核心概念(超全!)

C作为一门广泛使用的编程语言&#xff0c;以其高性能和灵活性在软件开发领域占据重要地位。无论是游戏开发、系统编程还是实时应用&#xff0c;C都是一个不可或缺的工具。本博客旨在为初学者提供C编程语言的核心概念&#xff0c;帮助你建立坚实的基础。 C关键字 C关键字是编程…

扫拖一体洗地机哪个好用?热门扫拖一体机品牌

扫拖一体洗地机是一种现代化的清洁设备&#xff0c;它可以帮助我们更快、更有效地清洁地面。这几年市面上的主流品牌纷纷更新迭代产品&#xff0c;那么&#xff0c;选择什么品牌的洗地机才是算是一个不错的选择呢&#xff1f;我们先了解下洗地机吧。 洗地机的功能与原理 市面…