注意:RRF 在 Elastic Stack 8.8 中正式提供。
倒數(shù)排序融合(RRF)是一種將具有不同相關(guān)性指標(biāo)的多個(gè)結(jié)果集組合成單個(gè)結(jié)果集的方法。 RRF 無(wú)需調(diào)優(yōu),不同的相關(guān)性指標(biāo)也不必相互關(guān)聯(lián)即可獲得高質(zhì)量的結(jié)果。該方法的優(yōu)勢(shì)在于不利用相關(guān)分?jǐn)?shù),而僅靠排名計(jì)算。相關(guān)分?jǐn)?shù)存在的問(wèn)題在于不同模型的分?jǐn)?shù)范圍差。
使用 Reciprocal Rank Fusion (RRF) 的簡(jiǎn)化混合搜索
通常,最好的排名是通過(guò)組合多種排名方法來(lái)實(shí)現(xiàn)的,例如 BM25 和生成密集向量嵌入的 ML 模型。 在實(shí)踐中,將結(jié)果集組合成一個(gè)單一的組合相關(guān)性排名結(jié)果集被證明是非常具有挑戰(zhàn)性的。 當(dāng)然,理論上你可以將每個(gè)結(jié)果集的分?jǐn)?shù)歸一化(因?yàn)樵挤謹(jǐn)?shù)在完全不同的范圍內(nèi)),然后進(jìn)行線性組合,根據(jù)每個(gè)排名的分?jǐn)?shù)加權(quán)和排序最終結(jié)果集方法。 只要你提供正確的權(quán)重,Elasticsearch 就支持它并且運(yùn)行良好。 為此,你需要了解環(huán)境中每種方法得分的統(tǒng)計(jì)分布,并有條不紊地優(yōu)化權(quán)重。 實(shí)際上,這超出了絕大多數(shù)用戶的能力。
另一種方法是 RRF 算法,它提供了出色的排序方法零樣本混合,正如學(xué)術(shù)研究所證明的那樣。 如果你不了解不同方法中排名分?jǐn)?shù)的確切分布,這不僅是最好的混合方式,而且客觀上也是混合排名方法的好方法 —— 即使你知道如何歸一化及分?jǐn)?shù)的分布情況,也很難被擊敗。 基本概念是結(jié)果的組合順序由每個(gè)結(jié)果集中每個(gè)文檔的位置(和存在)定義。 因此可以方便地忽略排名分?jǐn)?shù)。
Elastic 8.8 支持具有多個(gè)密集向量查詢和在倒排索引上運(yùn)行的單個(gè)查詢的 RRF。 在不久的將來(lái),我們希望支持來(lái)自 BM25 和 Elastic 的檢索模型(兩者都是稀疏向量)的混合結(jié)果,從而產(chǎn)生同類(lèi)最佳的零樣本集(無(wú)域內(nèi)訓(xùn)練)排名方法。
?
- D - 文檔集
- R - 一組排名作為 1..|D| 的排列
- K - 通常默認(rèn)設(shè)置為 60
RRF 使用以下公式來(lái)確定對(duì)每個(gè)文檔進(jìn)行排名的分?jǐn)?shù):
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
倒數(shù)排序融合 API
你可以將 RRF 用作搜索的一部分,以使用來(lái)自:
- 1 個(gè)查詢(query)和 1 個(gè)或多個(gè) kNN 搜索
- 2 個(gè)或更多 kNN 搜索
rrf 參數(shù)是一個(gè)可選對(duì)象,定義為搜索請(qǐng)求 rank parameter 的一部分。 rrf 對(duì)象包含以下參數(shù):
條目 | 描述 |
---|---|
rank_constant | (可選,整數(shù))此值確定每個(gè)查詢的單個(gè)結(jié)果集中的文檔對(duì)最終排名結(jié)果集的影響程度。 較高的值表示排名較低的文檔具有更大的影響力。 此值必須大于或等于 1。默認(rèn)為 60。 |
window_size | (可選,整數(shù))此值確定每個(gè)查詢的單個(gè)結(jié)果集的大小。 較高的值將以性能為代價(jià)提高結(jié)果相關(guān)性。 最終排名的結(jié)果集被修剪為搜索請(qǐng)求的 <<search-size-param, size>。 window_size 必須大于或等于 size 且大于或等于 1。默認(rèn)為 100。 |
使用 RRF 的示例請(qǐng)求:
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
}
}
}
在上面的示例中,我們首先執(zhí)行 kNN 搜索以獲取其全球前 50 名的結(jié)果。 然后我們執(zhí)行查詢以獲取其全球前 50 名的結(jié)果。 之后,在一個(gè)協(xié)調(diào)節(jié)點(diǎn)上,我們將 knn 搜索結(jié)果與查詢結(jié)果結(jié)合起來(lái),根據(jù) RRF 方法對(duì)它們進(jìn)行排序,得到最終的 top 10 結(jié)果。
請(qǐng)注意,如果來(lái)自 knn 搜索的 k 大于 window_size,則結(jié)果將被截?cái)酁?window_size。 如果 k 小于 window_size,則結(jié)果為 k 大小。
倒數(shù)排序融合支持的功能
RRF 確實(shí)支持:
- from
- aggregations
RRF 目前不支持:
- scroll
- point in time
- sort
- rescore
- suggesters
- highlighting
- collapse
- explain
- profiling
使用不支持的功能作為使用 RRF 的搜索的一部分將導(dǎo)致異常。
倒數(shù)排序融合完整示例
我們首先為具有文本字段、向量字段和整數(shù)字段的索引創(chuàng)建映射,同時(shí)索引多個(gè)文檔。 對(duì)于這個(gè)例子,我們將使用一個(gè)只有一個(gè)維度的向量來(lái)使排名更容易解釋。
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
現(xiàn)在,我們使用帶有查詢、kNN 搜索和術(shù)語(yǔ)聚合的 RRF 執(zhí)行搜索。
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 和術(shù)語(yǔ)聚合結(jié)果的響應(yīng)。 請(qǐng)注意,_score 為 null,我們改為使用 _rank 來(lái)顯示排名靠前的文檔。
{
"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
}
]
}
}
}
讓我們分解一下這些點(diǎn)擊率是如何排名的。 我們首先分別運(yùn)行查詢和 kNN 搜索,以收集它們各自的命中率。
首先,我們查看查詢的 hits。
GET example-index/_search?filter_path=**.hits
{
"query": {
"term": {
"text": "rrf"
}
}
}
上面的命令顯示的結(jié)果為:
{
"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
請(qǐng)注意,我們的第一個(gè)命中沒(méi)有 vector 字段的值。 現(xiàn)在,我們查看 kNN 搜索的結(jié)果。
GET example-index/_search?filter_path=**.hits
{
"knn": {
"field": "vector",
"query_vector": [
3
],
"k": 5,
"num_candidates": 5
}
}
上面搜索的結(jié)果為:
{
"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
我們現(xiàn)在可以獲取兩個(gè)單獨(dú)排名的結(jié)果集并將 RRF 公式應(yīng)用于它們以獲得我們的最終排名。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-482083.html
# 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
我們根據(jù) RRF 公式對(duì)文檔進(jìn)行排名,其中 window_size 為 5,截?cái)?RRF 結(jié)果集中底部的 2 個(gè)文檔,大小為 3。我們以 _id: 3 作為?_rank: 1, _id: 2 作為?_rank: 2, 及?_id: 4 作為?_rank: 3。這個(gè)排名符合預(yù)期的原始 RRF 搜索的結(jié)果集。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-482083.html
到了這里,關(guān)于Elasticsearch:倒數(shù)排序融合 - Reciprocal rank fusion的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!