在混合搜索中使用倒数排名融合 (RRF) 的相关性评分
倒数排名融合 (RRF) 是一种算法,可评估多个以前的排名结果中的搜索分数以生成统一的结果集。 在 Azure AI 搜索中,每当并行执行两个或更多个查询时,都会使用 RRF。 每个查询都会生成一个排名结果集,RRF 可用于将排名合并和同质化为单个结果集,在查询响应中返回。 始终使用 RRF 的示例方案包括混合搜索和并行执行的多个矢量查询。
RRF 基于倒数排名的概念,即搜索结果列表中第一个相关文档的排名的倒数。 该方法的目标是考虑项目在原始排名中的位置,并赋予在多个列表中排名较高的项目更高的重要性。 这有助于提高最终排名的整体质量和可靠性,使其对融合多个有序搜索结果的任务更加有用。
RRF 排名的工作原理
RRF 的工作方式是获取来自多种方法的搜索结果,为结果中的每个文档分配一个倒数排名分数,然后将这些分数结合起来创建一个新的排名。 其概念是,在多个搜索方法中出现在顶部位置的文档很可能相关度更高,因此应在合并结果中排名较高。
下面是 RRF 过程的简要说明:
从并行执行的多个查询中获取排名的搜索结果。
为每个排名列表中的结果分配倒数排名分数。 RRF 为每个结果集中的每个匹配项生成新的
@search.score
。 对于搜索结果中的每个文档,引擎基于其在列表中的位置分配倒数排名分数。 分数按1/(rank + k)
计算,其中rank
是文档在列表中的位置,k
是一个常量,经实验证明,如果将它设置为 60 这样较小的值,则效果最佳。 请注意,这个k
值是 RRF 算法中的常量,与控制最近的邻域数的k
完全不同。合并分数。 对于每个文档,引擎将从每个搜索系统中获得的倒数排名分数相加,为每个文档生成合并分数。
引擎根据合并分数对文档进行排名和排序。 得到的列表即为融合排名。
只有索引中标记为 searchable
或查询中标记为 searchFields
的字段才用于评分。 搜索结果中仅返回标记为 retrievable
的字段或在查询中的 select
中指定的字段,还会返回它们的搜索分数。
并行查询执行
每当有多个查询执行时,都会使用 RRF。 下面的示例演示了出现并行查询执行时的查询模式:
- 一个全文查询,加上一个矢量查询(简单的混合场景),等于两个查询执行。
- 一个全文查询,加上一个面向两个矢量字段的矢量查询,等于三个查询执行。
- 一个全文查询,加上两个面向五个矢量字段的矢量查询,等于 11 个查询执行
混合搜索结果中的分数
每次对结果排名时,@search.score
属性都包含用于对结果进行排序的值。 分数是由每种方法的排名算法生成的。 每种算法都有自己的范围和幅度。
下图标识了根据每个相关性排名算法的每个匹配项、算法和分数范围返回的评分属性。
搜索方法 | 参数 | 评分算法 | 范围 |
---|---|---|---|
全文搜索 | @search.score |
BM25 算法 | 没有上限。 |
矢量搜索 | @search.score |
HNSW 算法,使用 HNSW 配置中指定的相似性指标。 | 0.333 - 1.00(余弦),0 到 1(欧几里德和点积)。 |
混合搜索 | @search.score |
RRF 算法 | 上限受融合的查询数限制,每个查询对 RRF 分数的贡献最大约为 1。 例如,合并三个查询比只合并两个搜索结果生成的 RRF 分数更高。 |
混合查询响应中的排名结果数
默认情况下,如果你不使用分页,搜索引擎会返回全文搜索的前 50 个最高排名匹配项,以及矢量搜索的最相似的 k
匹配项。 在混合查询中,top
决定了响应中的结果数。 默认情况下,会返回统一结果集的前 50 个最高排名匹配项。
通常,搜索引擎会比 top
和 k
查找到更多结果。 要返回更多结果,请使用分页参数 top
、skip
和 next
。 分页是确定每个逻辑页面上的结果数并浏览完整有效负载的方式。
全文搜索的最大限制为 1,000 个匹配项(请参阅 API 响应限制)。 找到 1,000 个匹配项后,搜索引擎便不再进行查找。
有关详细信息,请参阅如何处理搜索结果。
搜索评分工作流的示意图
下图展示了混合查询,其调用关键字和矢量搜索,并通过计分概要文件进行提升。
生成之前的工作流的查询可能如以下所示:
POST https://{{search-service-name}}.search.azure.cn/indexes/{{index-name}}/docs/search?api-version=2023-11-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
"search":"hello world",
"searchFields":"field_a, field_b",
"vectorQueries": [
{
"kind":"vector",
"vector": [1.0, 2.0, 3.0],
"fields": "field_c, field_d"
},
{
"kind":"vector",
"vector": [4.0, 5.0, 6.0],
"fields": "field_d, field_e"
}
],
"scoringProfile":"my_scoring_profile"
}