하이브리드 검색: 전체 텍스트 및 kNN 결과 결합

이제 문서 모음을 검색하는 두 가지 다른 접근 방식과 각각 고유한 이점을 살펴보았습니다. 이러한 방법 중 하나가 사용자의 요구와 일치하면 다른 방법이 필요하지 않지만, 많은 경우 각 검색 방법이 다른 방법으로는 놓칠 수 있는 중요한 결과를 반환하므로 가장 좋은 방법은 결합된 결과 집합을 제공하는 것입니다.

이러한 경우를 위해 Elasticsearch는 두 개 이상의 목록의 결과를 단일 목록으로 결합하는 알고리즘인 상호 순위 융합을 제공합니다.

RRF 작동 방식

Elasticsearch는 RRF 알고리즘을 검색 쿼리에 통합합니다. 각각 전체 텍스트 및 벡터 검색을 요청하는 query 및 knn 섹션과 이를 단일 결과 목록으로 결합하는 rrf 섹션이 있는 다음 예시를 살펴보세요.

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

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)

이 버전에서는 각 검색 방법의 최상의 결과가 결합됩니다. 여기를 클릭하여 이러한 변경 사항이 포함된 전체 신청서를 검토하세요.

최첨단 검색 환경을 구축할 준비가 되셨나요?

충분히 고급화된 검색은 한 사람의 노력만으로는 달성할 수 없습니다. Elasticsearch는 여러분과 마찬가지로 검색에 대한 열정을 가진 데이터 과학자, ML 운영팀, 엔지니어 등 많은 사람들이 지원합니다. 서로 연결하고 협력하여 원하는 결과를 얻을 수 있는 마법 같은 검색 환경을 구축해 보세요.