はじめに
Elasticsearchはベクトル検索をサポートしてるためLangChainからベクトルストアとして取り扱うことができます。特に難しいことはないのですが動作する例で紹介します。
サンプルコード
ElasticsearchStoreを使うとドキュメントストアとしてElasticsearchを利用することができます。利用には以下のパッケージをimportしてください。
pip install elasticsearch
pip install langchain-elasticsearch
以下、LangChainのRetrieverとしてElasticsearchを扱い、ドキュメントをベクトル検索するサンプルコードです。
from elasticsearch import Elasticsearch
from langchain_elasticsearch import ElasticsearchStore, DenseVectorStrategy
# 接続情報を環境変数から取得
from dotenv import load_dotenv
import os
load_dotenv()
ES_CLOUD_ID = os.getenv('ES_CLOUD_ID')
ES_API_KEY = os.getenv('ES_API_KEY')
# Elasticsearchのインデックス名、モデルID等を指定
INDEX_NAME = "datasets-wikimedia_wikipedia-20231101.ja"
MODEL_ID = '.multilingual-e5-small_linux-x86_64'
VECTOR_QUERY_FIELD="text_semantic.inference.chunks.embeddings" # ベクトル検索するフィールド
QUERY_FIELD = "text" # BM25で検索するフィールド
# Elasticsearchに接続
es_client = Elasticsearch(
cloud_id=ES_CLOUD_ID,
api_key=ES_API_KEY,
request_timeout=60,
)
# Modelを指定してDenseVectorStrategyを作成(ハイブリッド検索を有効化)
strategy = DenseVectorStrategy(model_id=MODEL_ID, hybrid=True)
# ElasticsearchStoreを作成
store = ElasticsearchStore(
es_connection=es_client,
index_name=INDEX_NAME,
vector_query_field=VECTOR_QUERY_FIELD,
query_field=QUERY_FIELD,
strategy=strategy,
)
# クエリを発行
query = "日本の首都はどこですか?"
retriever = store.as_retriever()
docs = retriever.invoke(query)
コード内のコメントの通りなので特に追加する説明もないですね。。store.as_retriever()
でChainとして扱えるRetrieverが取得できるので、LCELに組み込んで使えます。またDenseVectorStrategyでhybrid=Trueとしているので、ベクトル検索とキーワード検索のハイブリッド検索を実行するようになっています。
ただし、見て分かる通りElasticsearchStoreを使う場合、クエリーのカスタマイズができません。本当にベクトル検索だけできれば良い、ということなら便利かもしれませんが、クエリーをチューニングしてパフォーマンスや関連度を向上させたい場合などは、通常のElasticsearchクライアントから普通にsearch()メソッドを使ったり、あるいはよりおすすめの方法としてはsearch_template()を使ったりした方が、自由にクエリーを組み立てられます。元も子もないのですが。
Search Templateについては以下の記事も参照してください。
おわりに
LangChainのElasticsearchStoreの使い方について紹介しました。既存のChainに組み込まれているRetrieverをElasticsearchStoreと別のもので条件によって切り替えたい、などの時は便利に使えるかもしれません。
単にElasticsearchをドキュメントストアとしてRAGを構築したい、という場合は無理やりChainに組み込まず、独自でElasticsearchへのクエリーを書いてそれをコンテキストとしてLLMに渡す、などでも問題ないと思いますので、必要に応じて使い分けてください。