GoogleColabで複数のリトリーバーの結果を組み合わせる方法
はじめに
EnsembleRetrieverとは
EnsembleRetriever
は、複数の異なるリトリーバーの結果を組み合わせて、より高精度な検索結果を得るためのクラスです。以下の図は、EnsembleRetriever
の概要を示しています。
EnsembleRetriever
は、BaseRetriever
を継承した複数のリトリーバーオブジェクトを受け取り、それぞれのリトリーバーの検索結果をアンサンブルします。アンサンブルには、Reciprocal Rank Fusion(RRF)アルゴリズムが使用されます。RRFは、各リトリーバーが返す結果の順位を考慮し、最終的な順位を決定します。
リトリーバーの種類
EnsembleRetriever
で組み合わせるリトリーバーには、主に2種類あります。
-
スパースリトリーバー(例: BM25)
- キーワードベースの検索に適しています。
- ドキュメント内の単語の出現頻度と、クエリとの関連性を考慮します。
-
密リトリーバー(例: 埋め込み類似度)
- 意味的類似性に基づく検索に適しています。
- ドキュメントとクエリの分散表現(埋め込み)を比較し、類似度を計算します。
スパースリトリーバーと密リトリーバーを組み合わせることで、それぞれの長所を活かした検索が可能になります。この組み合わせは「ハイブリッド検索」とも呼ばれています。
リトリーバーの種類 | 検索の基準 | 長所 | 短所 |
---|---|---|---|
スパースリトリーバー | キーワードの出現頻度と関連性 | 計算コストが低い キーワードマッチングに強い |
同義語や関連語への対応が弱い |
密リトリーバー | 意味的類似性 | 同義語や関連語への対応が強い | 計算コストが高い 埋め込みの質に依存 |
EnsembleRetriever
を使用することで、これらのリトリーバーの長所を組み合わせ、より高精度な検索結果を得ることができます。
基本的な使い方
以下では、BM25RetrieverとFAISSベクトルストアから派生したリトリーバーのアンサンブルを示します。
まず、必要なライブラリをインストールします。
# rank_bm25ライブラリをインストール
%pip install --upgrade --quiet rank_bm25 > /dev/null
次に、必要なモジュールをインポートします。
# EnsembleRetrieverをインポート
from langchain.retrievers import EnsembleRetriever
# BM25Retrieverをインポート
from langchain_community.retrievers import BM25Retriever
# FAISSベクトルストアをインポート
from langchain_community.vectorstores import FAISS
# OpenAIの埋め込みモデルをインポート
from langchain_openai import OpenAIEmbeddings
サンプルのドキュメントリストを用意します。
# BM25Retrieverで使用する日本語のドキュメントリスト
doc_list_1 = [
"私はリンゴが好きです",
"私はオレンジが好きです",
"リンゴとオレンジは果物です",
]
# FAISSリトリーバーで使用する日本語のドキュメントリスト
doc_list_2 = [
"あなたはリンゴが好きです",
"あなたはオレンジが好きです",
]
BM25リトリーバーとFAISSリトリーバーを初期化します。
# BM25リトリーバーを初期化
# doc_list_1からBM25リトリーバーを作成し、各ドキュメントにメタデータとしてsource=1を付与
bm25_retriever = BM25Retriever.from_texts(
doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1)
)
# 検索結果の数を2に設定
bm25_retriever.k = 2
# FAISSリトリーバーを初期化
# OpenAIの埋め込みモデルを使用
embedding = OpenAIEmbeddings()
# doc_list_2からFAISSベクトルストアを作成し、各ドキュメントにメタデータとしてsource=2を付与
faiss_vectorstore = FAISS.from_texts(
doc_list_2, embedding, metadatas=[{"source": 2}] * len(doc_list_2)
)
# FAISSベクトルストアからリトリーバーを作成し、検索結果の数を2に設定
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2})
アンサンブルリトリーバーを初期化します。
# アンサンブルリトリーバーを初期化
# BM25リトリーバーとFAISSリトリーバーを使用し、それぞれの重みを0.5に設定
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
)
アンサンブルリトリーバーを使用してドキュメントを取得します。
# "リンゴ"をクエリとしてアンサンブルリトリーバーを実行
docs = ensemble_retriever.invoke("リンゴ")
# 検索結果を表示
print(docs)
[Document(page_content='リンゴとオレンジは果物です', metadata={'source': 1}),
Document(page_content='あなたはリンゴが好きです', metadata={'source': 2}),
Document(page_content='私はオレンジが好きです', metadata={'source': 1}),
Document(page_content='あなたはオレンジが好きです', metadata={'source': 2})]
ランタイム設定
個々のリトリーバーをランタイム時に設定可能なフィールドを使用して設定することもできます。以下では、FAISSリトリーバーの"top-k"パラメータを更新します。
# ConfigurableFieldをインポート
from langchain_core.runnables import ConfigurableField
# FAISSリトリーバーを設定可能なフィールドで初期化
faiss_retriever = faiss_vectorstore.as_retriever(
search_kwargs={"k": 2}
).configurable_fields(
# 検索時のパラメータを設定可能なフィールドとして定義
search_kwargs=ConfigurableField(
id="search_kwargs_faiss",
name="Search Kwargs",
description="The search kwargs to use",
)
)
# アンサンブルリトリーバーを初期化
# BM25リトリーバーと設定可能なFAISSリトリーバーを使用し、それぞれの重みを0.5に設定
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
)
設定を使用してドキュメントを取得します。
# FAISSリトリーバーの検索結果の数を1に設定
config = {"configurable": {"search_kwargs_faiss": {"k": 1}}}
# "リンゴ"をクエリとしてアンサンブルリトリーバーを実行し、設定を適用
docs = ensemble_retriever.invoke("リンゴ", config=config)
# 検索結果を表示
print(docs)
[Document(page_content='リンゴとオレンジは果物です', metadata={'source': 1}),
Document(page_content='あなたはリンゴが好きです', metadata={'source': 2}),
Document(page_content='私はオレンジが好きです', metadata={'source': 1})]
FAISSリトリーバーの設定をランタイム時に関連する設定を渡したため、FAISSリトリーバーからは1つのソースしか返されないことに注意してください。
まとめ
本記事では、初心者でも理解できるように、GoogleColabで複数のリトリーバーの結果を組み合わせる方法について説明しました。
EnsembleRetrieverとは
- 複数の異なるリトリーバーの結果を組み合わせて、より高精度な検索結果を得るためのクラス
- Reciprocal Rank Fusion(RRF)アルゴリズムを使用してアンサンブル
- スパースリトリーバー(BM25など)と密リトリーバー(埋め込み類似度など)を組み合わせることが一般的
基本的な使い方
- 必要なライブラリをインストールし、モジュールをインポート
- サンプルのドキュメントリストを用意
- BM25リトリーバーとFAISSリトリーバーを初期化
- アンサンブルリトリーバーを初期化
- アンサンブルリトリーバーを使用してドキュメントを取得
ランタイム設定
- 個々のリトリーバーをランタイム時に設定可能なフィールドを使用して設定可能
ConfigurableField
を使用してFAISSリトリーバーの"top-k"パラメータを更新- 設定を使用してドキュメントを取得
EnsembleRetriever
を使用することで、異なるリトリーバーの長所を組み合わせ、より高精度な検索結果を得ることができます。本記事で紹介したサンプルコードを参考に、実際にGoogleColabで試してみることをおすすめします。APIリファレンスも参照しながら、様々な設定を試し、最適な組み合わせを見つけてください。
コメント