LlamaIndexとMilvusを用いた全文検索
全文検索では、キーワードの完全一致を利用し、多くの場合BM25などのアルゴリズムを活用して、関連性に基づいてドキュメントをランク付けします。検索拡張生成(RAG)システムでは、この手法を用いて関連性の高いテキストを取得し、AIが生成する応答の質を向上させます。
一方、セマンティック検索は文脈上の意味を解釈し、より広範な検索結果を提供します。これら2つのアプローチを組み合わせることでハイブリッド検索が実現され、特に単一の手法では不十分な場合において、情報検索の精度が向上します。
Milvus 2.5のSparse-BM25アプローチでは、生のテキストが自動的にスパースベクトルに変換されます。これにより、手動でのスパース埋め込み生成が不要となり、意味理解とキーワードの関連性のバランスを取ったハイブリッド検索戦略が可能になります。
このチュートリアルでは、LlamaIndexとMilvusを使用して、全文検索とハイブリッド検索を活用したRAGシステムを構築する方法を学びます。まず、全文検索のみを実装し、その後、より包括的な結果を得るためにセマンティック検索を統合して機能を強化していきます。
このチュートリアルを進める前に、全文検索およびLlamaIndexでのMilvusの使用方法の基本について理解していることを確認してください。
前提条件
依存関係のインストール
開始する前に、以下の依存関係がインストールされていることを確認してください:
$ $pip install llama-index-vector-stores-milvus
$ $pip install llama-index-embeddings-openai
$ $pip install llama-index-llms-openai
Google Colab を使用している場合は、ランタイムを再起動する必要がある場合があります(インターフェース上部の「Runtime」メニューに移動し、ドロップダウンメニューから「Restart session」を選択してください)。
アカウントの設定
このチュートリアルでは、テキストの埋め込みおよび回答生成に OpenAI を使用します。OpenAI API キーを準備する必要があります。
import openai
openai.api_key = "sk-"
Milvusベクトルストアを使用するには、MilvusサーバーのURI を指定してください(必要に応じてTOKEN も指定できます)。Milvusサーバーを起動するには、Milvusのインストールガイドに従ってサーバーを設定するか、Zilliz Cloudを無料で試用してください。
全文検索は現在、Milvus Standalone、Milvus Distributed、およびZilliz Cloudでサポートされていますが、Milvus Liteではまだサポートされていません(将来の実装を予定しています)。詳細については、support@zilliz.com までお問い合わせください。
URI = "http://localhost:19530"
# TOKEN = ""
サンプルデータのダウンロード
以下のコマンドを実行して、サンプルドキュメントを「data/paul_graham」ディレクトリにダウンロードしてください:
$ mkdir -p 'data/paul_graham/'
$ $wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
--2025-03-27 07:49:01-- https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 75042 (73K) [text/plain]
Saving to: ‘data/paul_graham/paul_graham_essay.txt’
data/paul_graham/pa 100%[===================>] 73.28K --.-KB/s in 0.07s
2025-03-27 07:49:01 (1.01 MB/s) - ‘data/paul_graham/paul_graham_essay.txt’ saved [75042/75042]
全文検索を備えたRAG
RAGシステムに全文検索を統合することで、セマンティック検索と、正確かつ予測可能なキーワードベースの検索とのバランスを取ることができます。全文検索のみを使用することも可能ですが、より良い検索結果を得るためには、全文検索とセマンティック検索を組み合わせることをお勧めします。ここでは、デモの目的で、全文検索のみとハイブリッド検索の両方をご紹介します。
まず、SimpleDirectoryReaderLoad を使用して、ポール・グラハムによるエッセイ「What I Worked On」を読み込みます:
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data/paul_graham/").load_data()
# Let's take a look at the first document
print("Example document:\n", documents[0])
Example document:
Doc ID: 16b7942f-bf1a-4197-85e1-f31d51ea25a9
Text: What I Worked On February 2021 Before college the two main
things I worked on, outside of school, were writing and programming. I
didn't write essays. I wrote what beginning writers were supposed to
write then, and probably still are: short stories. My stories were
awful. They had hardly any plot, just characters with strong feelings,
which I ...
BM25 による全文検索
LlamaIndexのMilvusVectorStore は全文検索をサポートしており、効率的なキーワードベースの検索を可能にします。sparse_embedding_function などの組み込み関数を使用することで、BM25スコアリングを適用して検索結果の順位付けを行います。
このセクションでは、全文検索にBM25を使用したRAGシステムの実装方法を解説します。
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.vector_stores.milvus.utils import BM25BuiltInFunction
from llama_index.core import Settings
# Skip dense embedding model
Settings.embed_model = None
# Build Milvus vector store creating a new collection
vector_store = MilvusVectorStore(
uri=URI,
# token=TOKEN,
enable_dense=False,
enable_sparse=True, # Only enable sparse to demo full text search
sparse_embedding_function=BM25BuiltInFunction(),
overwrite=True,
)
# Store documents in Milvus
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
Embeddings have been explicitly disabled. Using MockEmbedding.
上記のコードは、Milvusにサンプルドキュメントを挿入し、全文検索でBM25によるランク付けを可能にするインデックスを構築します。また、dense embeddingを無効にし、デフォルトのパラメータでBM25BuiltInFunction を利用します。
BM25BuiltInFunction のパラメータで、入力フィールドと出力フィールドを指定できます:
input_field_names (str): 入力テキストフィールド(デフォルト: “text”)。BM25アルゴリズムが適用されるテキストフィールドを示します。テキストフィールド名が異なる独自のコレクションを使用する場合は、これを変更してください。output_field_names (str): このBM25関数の出力が格納されるフィールド(デフォルト:「sparse_embedding」)。
ベクトルストアの設定が完了したら、Milvusのクエリモード「sparse」または「text_search」を使用して全文検索クエリを実行できます:
import textwrap
query_engine = index.as_query_engine(
vector_store_query_mode="sparse", similarity_top_k=5
)
answer = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(answer), 100))
The author learned several important lessons at Viaweb. They learned about the importance of growth
rate as the ultimate test of a startup, the value of building stores for users to understand retail
and software usability, and the significance of being the "entry level" option in a market.
Additionally, they discovered the accidental success of making Viaweb inexpensive, the challenges of
hiring too many people, and the relief felt when the company was acquired by Yahoo.
テキストアナライザーのカスタマイズ
アナライザーは、文をトークンに分割し、ステミングやストップワードの除去といった語彙処理を行うことで、全文検索において極めて重要な役割を果たします。これらは通常、言語ごとに異なります。詳細については、『Milvus アナライザーガイド』を参照してください。
Milvus は、「組み込みアナライザー」と「カスタムアナライザー」の 2 種類のアナライザーをサポートしています。デフォルトでは、BM25BuiltInFunction は標準の組み込みアナライザーを使用し、句読点に基づいてテキストをトークン化します。
別のアナライザーを使用したり、既存のアナライザーをカスタマイズしたりするには、analyzer_params 引数に値を指定します:
bm25_function = BM25BuiltInFunction(
analyzer_params={
"tokenizer": "standard",
"filter": [
"lowercase", # Built-in filter
{"type": "length", "max": 40}, # Custom cap size of a single token
{"type": "stop", "stop_words": ["of", "to"]}, # Custom stopwords
],
},
enable_match=True,
)
リランカーを用いたハイブリッド検索
ハイブリッド検索システムは、セマンティック検索と全文検索を組み合わせ、RAGシステムにおける検索パフォーマンスを最適化します。
以下の例では、セマンティック検索に OpenAI エンベディングを、全文検索に BM25 を使用しています:
# Create index over the documnts
vector_store = MilvusVectorStore(
uri=URI,
# token=TOKEN,
# enable_dense=True, # enable_dense defaults to True
dim=1536,
enable_sparse=True,
sparse_embedding_function=BM25BuiltInFunction(),
overwrite=True,
# hybrid_ranker="RRFRanker", # hybrid_ranker defaults to "RRFRanker"
# hybrid_ranker_params={}, # hybrid_ranker_params defaults to {}
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
embed_model="default", # "default" will use OpenAI embedding
)
仕組み
このアプローチでは、ドキュメントを、両方のベクトルフィールドを含むMilvusコレクションに格納します:
embedding: セマンティック検索用にOpenAIの埋め込みモデルによって生成された高密度埋め込み。sparse_embedding: 全文検索用にBM25BuiltInFunctionを使用して計算されたスパース埋め込み。
さらに、デフォルトパラメータを設定した「RRFRanker」を用いた再ランク付け戦略を適用しています。再ランク付け機能をカスタマイズするには、Milvusの再ランク付けガイドに従って、hybrid_ranker およびhybrid_ranker_params を設定することができます。
それでは、サンプルクエリを使用してRAGシステムをテストしてみましょう:
# Query
query_engine = index.as_query_engine(
vector_store_query_mode="hybrid", similarity_top_k=5
)
answer = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(answer), 100))
The author learned several important lessons at Viaweb. These included the importance of
understanding growth rate as the ultimate test of a startup, the impact of hiring too many people,
the challenges of being at the mercy of investors, and the relief experienced when Yahoo bought the
company. Additionally, the author learned about the significance of user feedback, the value of
building stores for users, and the realization that growth rate is crucial for the long-term success
of a startup.
このハイブリッドなアプローチにより、セマンティック検索とキーワードベースの検索の両方を活用することで、RAGシステムにおいてより正確で文脈を意識した応答を実現します。