混合搜索:综合全文和 kNN 结果

您现在已经看到了搜索文档集的两种不同方法,每种方法都有其独特的优势。但在许多情况下,每种搜索方法都会返回另一种方法所忽略的有价值的结果,因此最好的选择是提供一个组合结果集。

针对这些情况,Elasticsearch 提供了 "互惠排名融合"(Reciprocal Rank Fusion)算法,可将两个或多个列表中的结果合并为一个列表。

RRF 如何运作

Elasticsearch 将 RRF 算法集成到搜索查询中。请看下面的示例,其中queryknn 部分分别用于请求全文检索和矢量搜索,而rrf 部分则将它们合并为一个结果列表。

self.es.search(
    query={
        # full-text search query here
    },
    knn={
        # vector search query here
    },
    rank={
        "rrf": {}
    }
)

虽然 RRF 不需要任何配置就能很好地处理简短的结果列表,但有些参数是可以调整的,以提供最佳结果。如需详细了解这些信息,请查阅文档

经常资源框架的实施

要实现同时从全文和矢量搜索方法中返回结果的组合搜索,就必须重新使用handle_search() 功能中早先使用的全文搜索逻辑。要实施混合搜索策略,search() 方法必须同时接收queryknn 参数,每个参数都请求单独的查询。此外,还添加了上图所示的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)

该版本综合了每种搜索方法的最佳结果。单击此处查看包含这些更改的完整申请表。

准备好打造最先进的搜索体验了吗?

足够先进的搜索不是一个人的努力就能实现的。Elasticsearch 由数据科学家、ML 操作员、工程师以及更多和您一样对搜索充满热情的人提供支持。让我们联系起来,共同打造神奇的搜索体验,让您获得想要的结果。

亲自试用