混合搜索:综合全文和 kNN 结果
您现在已经看到了搜索文档集的两种不同方法,每种方法都有其独特的优势。但在许多情况下,每种搜索方法都会返回另一种方法所忽略的有价值的结果,因此最好的选择是提供一个组合结果集。
针对这些情况,Elasticsearch 提供了 "互惠排名融合"(Reciprocal Rank Fusion)算法,可将两个或多个列表中的结果合并为一个列表。
RRF 如何运作
Elasticsearch 将 RRF 算法集成到搜索查询中。请看下面的示例,其中query 和knn 部分分别用于请求全文检索和矢量搜索,而rrf 部分则将它们合并为一个结果列表。
self.es.search(
query={
# full-text search query here
},
knn={
# vector search query here
},
rank={
"rrf": {}
}
)虽然 RRF 不需要任何配置就能很好地处理简短的结果列表,但有些参数是可以调整的,以提供最佳结果。如需详细了解这些信息,请查阅文档。
经常资源框架的实施
要实现同时从全文和矢量搜索方法中返回结果的组合搜索,就必须重新使用handle_search() 功能中早先使用的全文搜索逻辑。要实施混合搜索策略,search() 方法必须同时接收query 和knn 参数,每个参数都请求单独的查询。此外,还添加了上图所示的rank 部分,以便将结果合并为一个排序列表。
以下是实施混合搜索策略的handle_search() 版本:
@app.post('/')
def handle_search():
query = request.form.get('query', '')
filters, parsed_query = extract_filters(query)
from_ = request.form.get('from_', type=int, default=0)
if parsed_query:
search_query = {
'must': {
'multi_match': {
'query': parsed_query,
'fields': ['name', 'summary', 'content'],
}
}
}
else:
search_query = {
'must': {
'match_all': {}
}
}
results = es.search(
query={
'bool': {
**search_query,
**filters
}
},
knn={
'field': 'embedding',
'query_vector': es.get_embedding(parsed_query),
'k': 10,
'num_candidates': 50,
**filters,
},
rank={
'rrf': {}
},
aggs={
'category-agg': {
'terms': {
'field': 'category.keyword',
}
},
'year-agg': {
'date_histogram': {
'field': 'updated_at',
'calendar_interval': 'year',
'format': 'yyyy',
},
},
},
size=5,
from_=from_,
)
aggs = {
'Category': {
bucket['key']: bucket['doc_count']
for bucket in results['aggregations']['category-agg']['buckets']
},
'Year': {
bucket['key_as_string']: bucket['doc_count']
for bucket in results['aggregations']['year-agg']['buckets']
if bucket['doc_count'] > 0
},
}
return render_template('index.html', results=results['hits']['hits'],
query=query, from_=from_,
total=results['hits']['total']['value'], aggs=aggs)该版本综合了每种搜索方法的最佳结果。单击此处查看包含这些更改的完整申请表。