ハイブリッド検索: 全文検索とkNN検索結果の組み合わせ
これまで、ドキュメントのコレクションを検索するための 2 つの異なるアプローチを見てきました。それぞれのアプローチには独自の利点があります。これらの方法のいずれかがニーズに合致する場合は、他の方法は必要ありませんが、多くの場合、各検索方法では、他の方法では得られない貴重な結果が返されるため、結合された結果セットを提供することが最善の選択肢となります。
このような場合に備えて、Elasticsearch は、2 つ以上のリストの結果を 1 つのリストに結合するアルゴリズムである Reciprocal Rank Fusionを提供します。
RRFの仕組み
Elasticsearch は RRF アルゴリズムを検索クエリに統合します。次の例を考えてみましょう。この例には、それぞれ全文検索とベクター検索を要求するqueryセクションとknnセクションがあり、それらを 1 つの結果リストに結合する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セクションも追加され、結果が 1 つのランク付けされたリストに結合されます。
ハイブリッド検索戦略を実装する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)このバージョンでは、各検索方法からの最良の結果が結合されます。変更を加えた完全な申請書を確認するには、ここをクリックしてください。