LlamaIndexとmilvusによるメタデータフィルタリング
このノートブックでは、LlamaIndexにおけるMilvusベクターストアの使用方法について、メタデータフィルタリング機能を中心に説明します。LlamaIndexに内蔵されたメタデータフィルタを使ったベクトル検索、Milvusのネイティブフィルタリング式のベクトルストアへの適用方法を学びます。
このノートブックを終える頃には、Milvusのフィルタリング機能を活用し、ドキュメントのメタデータに基づいて検索結果を絞り込む方法を理解できるようになるでしょう。
前提条件
依存関係のインストール
始める前に、以下の依存関係がインストールされていることを確認してください:
$ pip install llama-index-vector-stores-milvus llama-index
Google Colabを使用している場合、ランタイムを再起動する必要があるかもしれません(インターフェースの上部にある "Runtime "メニューに移動し、ドロップダウンメニューから "Restart session "を選択してください)。
アカウントの設定
このチュートリアルでは、テキスト埋め込みと回答生成にOpenAIを使います。OpenAIのAPIキーを準備する必要があります。
import openai
openai.api_key = "sk-"
Milvusベクターストアを使用するには、MilvusサーバをURI (オプションでTOKEN)で指定します。Milvusサーバを立ち上げるには、Milvusインストールガイドに従うか、Zilliz Cloudを無料で試すことができます。
URI = "./milvus_filter_demo.db" # Use Milvus-Lite for demo purpose
# TOKEN = ""
データの準備
今回の例では、タイトルは似たり寄ったりだが、メタデータ(著者、ジャンル、出版年)が異なる書籍を数冊、サンプルデータとして使用する。これにより、Milvusがベクトルの類似度とメタデータの属性の両方に基づいて文書をフィルタリングし、検索する方法を示すことができます。
from llama_index.core.schema import TextNode
nodes = [
TextNode(
text="Life: A User's Manual",
metadata={
"author": "Georges Perec",
"genre": "Postmodern Fiction",
"year": 1978,
},
),
TextNode(
text="Life and Fate",
metadata={
"author": "Vasily Grossman",
"genre": "Historical Fiction",
"year": 1980,
},
),
TextNode(
text="Life",
metadata={
"author": "Keith Richards",
"genre": "Memoir",
"year": 2010,
},
),
TextNode(
text="The Life",
metadata={
"author": "Malcolm Knox",
"genre": "Literary Fiction",
"year": 2011,
},
),
]
インデックスの構築
このセクションでは、デフォルトの埋め込みモデル(OpenAIのtext-embedding-ada-002 )を使用して、Milvusにサンプルデータを格納します。タイトルはテキスト埋め込みに変換され、密な埋め込みフィールドに格納され、すべてのメタデータはスカラーフィールドに格納されます。
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.core import StorageContext, VectorStoreIndex
vector_store = MilvusVectorStore(
uri=URI,
# token=TOKEN,
collection_name="test_filter_collection", # Change collection name here
dim=1536, # Vector dimension depends on the embedding model
overwrite=True, # Drop collection if exists
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)
2025-04-22 08:31:09,871 [DEBUG][_create_connection]: Created new connection using: 19675caa8f894772b3db175b65d0063a (async_milvus_client.py:547)
メタデータ・フィルター
このセクションでは、LlamaIndexの組み込みメタデータフィルタと条件をmilvus検索に適用する。
メタデータフィルタの定義
from llama_index.core.vector_stores import (
MetadataFilter,
MetadataFilters,
FilterOperator,
)
filters = MetadataFilters(
filters=[
MetadataFilter(
key="year", value=2000, operator=FilterOperator.GT
) # year > 2000
]
)
フィルタを使ったベクターストアからの検索
retriever = index.as_retriever(filters=filters, similarity_top_k=5)
result_nodes = retriever.retrieve("Books about life")
for node in result_nodes:
print(node.text)
print(node.metadata)
print("\n")
The Life
{'author': 'Malcolm Knox', 'genre': 'Literary Fiction', 'year': 2011}
Life
{'author': 'Keith Richards', 'genre': 'Memoir', 'year': 2010}
複数のメタデータフィルタ
複数のメタデータフィルタを組み合わせて、より複雑なクエリを作成することもできます。LlamaIndex は、AND とOR の両方の条件をサポートしています。これにより、メタデータ属性に基づいた、より正確で柔軟な文書の検索が可能になります。
条件AND
1979年から2010年の間に出版された書籍(具体的には、1979 < year ≤ 2010)を検索する例を試してみましょう:
from llama_index.core.vector_stores import FilterCondition
filters = MetadataFilters(
filters=[
MetadataFilter(
key="year", value=1979, operator=FilterOperator.GT
), # year > 1979
MetadataFilter(
key="year", value=2010, operator=FilterOperator.LTE
), # year <= 2010
],
condition=FilterCondition.AND,
)
retriever = index.as_retriever(filters=filters, similarity_top_k=5)
result_nodes = retriever.retrieve("Books about life")
for node in result_nodes:
print(node.text)
print(node.metadata)
print("\n")
Life and Fate
{'author': 'Vasily Grossman', 'genre': 'Historical Fiction', 'year': 1980}
Life
{'author': 'Keith Richards', 'genre': 'Memoir', 'year': 2010}
条件OR
Georges PerecかKeith Richardsのどちらかによって書かれた本をフィルタリングする別の例を試してみてください:
filters = MetadataFilters(
filters=[
MetadataFilter(
key="author", value="Georges Perec", operator=FilterOperator.EQ
), # author is Georges Perec
MetadataFilter(
key="author", value="Keith Richards", operator=FilterOperator.EQ
), # author is Keith Richards
],
condition=FilterCondition.OR,
)
retriever = index.as_retriever(filters=filters, similarity_top_k=5)
result_nodes = retriever.retrieve("Books about life")
for node in result_nodes:
print(node.text)
print(node.metadata)
print("\n")
Life
{'author': 'Keith Richards', 'genre': 'Memoir', 'year': 2010}
Life: A User's Manual
{'author': 'Georges Perec', 'genre': 'Postmodern Fiction', 'year': 1978}
Milvusのキーワード引数を使う
組み込みのフィルタリング機能に加えて、Milvusのネイティブなフィルタリング式をstring_expr キーワード引数で使用することができます。これにより、検索操作中に特定のフィルタリング式をMilvusに直接渡すことができ、標準的なメタデータフィルタリングだけでなく、Milvusの高度なフィルタリング機能を利用することができます。
Milvusは強力で柔軟なフィルタリングオプションを提供し、ベクトルデータの正確なクエリを可能にします:
- 基本演算子:比較演算子、範囲フィルタ、算術演算子、論理演算子
- フィルタ式テンプレート:一般的なフィルタリングシナリオ用の定義済みパターン
- 特殊演算子:JSONや配列フィールドのデータ型固有の演算子
Milvusフィルタリング式の包括的なドキュメントと例については、Milvusフィルタリングの公式ドキュメントを参照してください。
retriever = index.as_retriever(
vector_store_kwargs={
"string_expr": "genre like '%Fiction'",
},
similarity_top_k=5,
)
result_nodes = retriever.retrieve("Books about life")
for node in result_nodes:
print(node.text)
print(node.metadata)
print("\n")
The Life
{'author': 'Malcolm Knox', 'genre': 'Literary Fiction', 'year': 2011}
Life and Fate
{'author': 'Vasily Grossman', 'genre': 'Historical Fiction', 'year': 1980}
Life: A User's Manual
{'author': 'Georges Perec', 'genre': 'Postmodern Fiction', 'year': 1978}