メインコンテンツまでスキップ

Elasticsearch クエリから Milvus への変換

Elasticsearch は Apache Lucene を基盤とする、代表的なオープンソースの検索エンジンです。しかし、モダンな AI アプリケーションでは、更新コストの高さ、リアルタイム性の低さ、非効率なシャード管理、クラウドネイティブではない設計、過剰なリソース要求など、さまざまな課題に直面します。クラウドネイティブなベクトルデータベースである Milvus は、ストレージとコンピューティングの分離、高次元データ向けの効率的なインデックス作成、モダンなインフラストラクチャとのシームレスな統合によって、これらの課題を克服します。AI ワークロードに対して優れたパフォーマンスとスケーラビリティを提供します。

この記事は、Elasticsearch から Milvus へのコードベースの移行を容易にすることを目的としており、両者間でクエリを変換するさまざまな例を提供します。

概要​

Elasticsearch では、クエリコンテキストの操作は関連性スコアを生成しますが、フィルターコンテキストの操作は生成しません。同様に、Milvus の検索は類似度スコアを生成しますが、フィルターのようなクエリは生成しません。Elasticsearch から Milvus へコードベースを移行する際の重要な原則は、Elasticsearch のクエリコンテキストで使用されるフィールドをベクトルフィールドに変換し、類似度スコアを生成できるようにすることです。

次の表に、いくつかの Elasticsearch クエリパターンと、それに対応する Milvus の等価な機能を示します。

Elasticsearch クエリ

Milvus の等価な機能

備考

全文クエリ

Match クエリ

全文検索

どちらも同様の機能セットを提供します。

タームレベルクエリ

ID

in 演算子

これらの Elasticsearch クエリをフィルターコンテキストで使用する場合、どちらも同一または同様の機能セットを提供します。

Prefix クエリ

like 演算子

Range クエリ

>、<、>=、<= などの比較演算子

Term クエリ

== などの比較演算子

Terms クエリ

in 演算子

Wildcard クエリ

like 演算子

Boolean クエリ

AND などの論理演算子

フィルターコンテキストで使用する場合、どちらも同様の機能セットを提供します。

ベクトルクエリ

kNN クエリ

検索

Milvus はより高度なベクトル検索機能を提供します。

Reciprocal Rank Fusion

ハイブリッド検索

Milvus は複数のリランキング戦略をサポートします。

全文クエリ​

Elasticsearch では、全文クエリを使用すると、メール本文など、解析済みのテキストフィールドを検索できます。クエリ文字列は、インデックス作成時にそのフィールドに適用されたものと同じアナライザーを使用して処理されます。

Match クエリ​

Elasticsearch では、Match クエリは、指定されたテキスト、数値、日付、またはブール値に一致するドキュメントを返します。指定されたテキストは、マッチングの前に解析されます。

以下は、Match クエリを使用した Elasticsearch 検索リクエストの例です。

python
resp = client.search(
query={
"match": {
"message": {
"query": "this is a test"
}
}
},
)

Milvus は、全文検索機能を通じて同じ機能を提供します。上記の Elasticsearch クエリは、次のようにして Milvus に変換できます。

python
res = client.search(
collection_name="my_collection",
data=['How is the weather in Jamaica?'],
anns_field="message_sparse",
output_fields=["id", "message"]
)

上記の例では、message_sparse は message という名前の VarChar フィールドから派生したスパースベクトルフィールドです。Milvus は BM25 埋め込みモデルを使用して、message フィールドの値をスパースベクトル埋め込みに変換し、message_sparse フィールドに格納します。検索リクエストを受信すると、Milvus は同じ BM25 モデルを使用してプレーンテキストのクエリペイロードを埋め込み、スパースベクトル検索を実行して、output_fields パラメーターで指定された id フィールドと message フィールドを、対応する類似度スコアとともに返します。

この機能を使用するには、message フィールドでアナライザーを有効にし、そこから message_sparse フィールドを派生させる関数を定義する必要があります。Milvus でアナライザーを有効にして派生関数を作成する詳細な手順については、全文検索 を参照してください。

タームレベルクエリ​

Elasticsearch では、タームレベルクエリは、日付範囲、IP アドレス、価格、製品 ID などの構造化データ内の正確な値に基づいてドキュメントを検索するために使用します。このセクションでは、一部の Elasticsearch タームレベルクエリに対応する Milvus の等価な機能について説明します。このセクションのすべての例は、Milvus の機能に合わせてフィルターコンテキスト内で動作するように調整されています。

ID​

Elasticsearch では、次のように、フィルターコンテキストで ID に基づいてドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"ids": {
"values": [
"1",
"4",
"100"
]
}
}
}
},
)

Milvus では、次のように、ID に基づいてエンティティを検索することもできます。

python
# Use the filter parameter
res = client.query(
collection_name="my_collection",
filter="id in [1, 4, 100]",
output_fields=["id", "title"]
)

# Use the ids parameter
res = client.query(
collection_name="my_collection",
ids=[1, 4, 100],
output_fields=["id", "title"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus のクエリおよび get リクエストとフィルター式の詳細については、クエリ および フィルタリングの説明 を参照してください。

Prefix クエリ​

Elasticsearch では、次のように、フィルターコンテキストで、指定されたフィールドに特定のプレフィックスを含むドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"prefix": {
"user": {
"value": "ki"
}
}
}
}
},
)

Milvus では、次のように、値が指定されたプレフィックスで始まるエンティティを検索できます。

python
res = client.query(
collection_name="my_collection",
filter='user like "ki%"',
output_fields=["id", "user"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus の like 演算子の詳細については、パターンマッチングでLIKE を使用する方法 を参照してください。

Range クエリ​

Elasticsearch では、次のように、指定された範囲内の用語を含むドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"range": {
"age": {
"gte": 10,
"lte": 20
}
}
}
}
},
)

Milvus では、次のように、特定のフィールドの値が指定された範囲内にあるエンティティを検索できます。

python
res = client.query(
collection_name="my_collection",
filter='10 <= age <= 20',
output_fields=["id", "user", "age"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus の比較演算子の詳細については、比較演算子 を参照してください。

Term クエリ​

Elasticsearch では、次のように、指定されたフィールドに完全一致する用語を含むドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"term": {
"status": {
"value": "retired"
}
}
}
}
},
)

Milvus では、次のように、指定されたフィールドの値が指定された用語と完全に一致するエンティティを検索できます。

python
# use ==
res = client.query(
collection_name="my_collection",
filter='status=="retired"',
output_fields=["id", "user", "status"]
)

# use TEXT_MATCH
res = client.query(
collection_name="my_collection",
filter='TEXT_MATCH(status, "retired")',
output_fields=["id", "user", "status"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus の比較演算子の詳細については、比較演算子 を参照してください。

Terms クエリ​

Elasticsearch では、次のように、指定されたフィールドに 1 つ以上の完全一致する用語を含むドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"terms": {
"degree": [
"graduate",
"post-graduate"
]
}
}
}
}
)

Milvus には、これに完全に相当する機能はありません。ただし、次のように、指定されたフィールドの値が指定された用語のいずれかであるエンティティを検索できます。

python
# use in
res = client.query(
collection_name="my_collection",
filter='degree in ["graduate", "post-graduate"]',
output_fields=["id", "user", "degree"]
)

# use TEXT_MATCH
res = client.query(
collection_name="my_collection",
filter='TEXT_MATCH(degree, "graduate post-graduate")',
output_fields=["id", "user", "degree"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus の範囲演算子の詳細については、範囲演算子 を参照してください。

Wildcard クエリ​

Elasticsearch では、次のように、ワイルドカードパターンに一致する用語を含むドキュメントを検索できます。

python
resp = client.search(
query={
"bool": {
"filter": {
"wildcard": {
"user": {
"value": "ki*y"
}
}
}
}
},
)

Milvus はフィルター条件でワイルドカードをサポートしていません。ただし、次のように、like 演算子を使用して同様の効果を得ることができます。

python
res = client.query(
collection_name="my_collection",
filter='user like "ki%" AND user like "%y"',
output_fields=["id", "user"]
)

Elasticsearch の例は、こちらのページ にあります。Milvus の範囲演算子の詳細については、範囲演算子 を参照してください。

Boolean クエリ​

Elasticsearch では、Boolean クエリは、他のクエリのブール組み合わせに一致するドキュメントにマッチするクエリです。

次の例は、こちらのページ にある Elasticsearch ドキュメントの例を基にしています。このクエリは、名前に kimchy を含み、production タグを持つユーザーを返します。

python
resp = client.search(
query={
"bool": {
"filter": {
"term": {
"user": "kimchy"
}
},
"filter": {
"term": {
"tags": "production"
}
}
}
},
)

Milvus では、次のように同様のことができます。

python
res = client.query(
collection_name="my_collection",
filter='user like "%kimchy%" AND ARRAY_CONTAINS(tags, "production")',
output_fields=["id", "user", "age", "tags"]
)

上記の例は、対象のコレクションに VarChar 型の user フィールドと Array 型の tags フィールドがあることを前提としています。このクエリは、名前に kimchy を含み、production タグを持つユーザーを返します。

ベクトルクエリ​

Elasticsearch では、ベクトルクエリは、ベクトルフィールドを操作してセマンティック検索を効率的に実行するための特殊なクエリです。

kNN クエリ​

Elasticsearch は、近似 kNN クエリと、正確なブルートフォース kNN クエリの両方をサポートしています。次のように、どちらの方法でも、類似度メトリクスで測定された、クエリベクトルに最も近い k 個のベクトルを見つけることができます。

python
resp = client.search(
index="my-image-index",
size=3,
query={
"knn": {
"field": "image-vector",
"query_vector": [
-5,
9,
-12
],
"k": 10
}
},
)

専用のベクトルデータベースである Milvus は、インデックスタイプを使用してベクトル検索を最適化します。通常、高次元ベクトルデータには近似最近傍(ANN)検索を優先します。FLAT インデックスタイプを使用したブルートフォース kNN 検索は正確な結果を返しますが、時間とリソースの両方を消費します。これに対し、AUTOINDEX やその他のインデックスタイプを使用した ANN 検索は、速度と精度のバランスを取り、kNN よりも大幅に高速でリソース効率の高いパフォーマンスを提供します。インデックスタイプと AUTOINDEX の詳細については、インデックス および AUTOINDEX の説明 を参照してください。

上記のベクトルクエリに相当する Milvus の同様の例は、次のとおりです。

python
res = client.search(
collection_name="my_collection",
anns_field="image-vector",
data=[[-5, 9, -12]],
limit=10
)

Elasticsearch の例は、こちらのページ にあります。Milvus の ANN 検索の詳細については、基本的な ANN 検索 を参照してください。

Reciprocal Rank Fusion​

Elasticsearch は、Reciprocal Rank Fusion(RRF)を提供し、異なる関連性指標を持つ複数の結果セットを 1 つのランク付けされた結果セットに統合します。

次の例は、検索の関連性を向上させるために、従来のタームベースの検索と k 最近傍(kNN)ベクトル検索を組み合わせる方法を示しています。

python
client.search(
index="my_index",
size=10,
query={
"retriever": {
"rrf": {
"retrievers": [
{
"standard": {
"query": {
"term": {
"text": "shoes"
}
}
}
},
{
"knn": {
"field": "vector",
"query_vector": [1.25, 2, 3.5], # Example vector; replace with your actual query vector
"k": 50,
"num_candidates": 100
}
}
],
"rank_window_size": 50,
"rank_constant": 20
}
}
}
)

この例では、RRF は 2 つのレトリーバーの結果を統合します。

  • text フィールドに "shoes" という用語を含むドキュメントに対する標準的なタームベース検索。

  • 指定されたクエリベクトルを使用した、vector フィールドに対する kNN 検索。

各レトリーバーは最大 50 件の上位一致を提供し、それらは RRF によって再ランク付けされ、最終的な上位 10 件の結果が返されます。

Milvus では、複数のベクトルフィールドにわたる検索を組み合わせ、リランキング戦略を適用し、統合されたリストから上位 K 件の結果を取得することで、同様のハイブリッド検索を実現できます。Milvus は RRF と重み付きリランカーの両方の戦略をサポートしています。詳細については、Weighted Ranker とその関連ページを参照してください。

以下は、上記の Elasticsearch の例に相当する、Milvus における厳密ではない等価な実装です。

python
from pymilvus import AnnSearchRequest, RRFRanker

search_params_dense = {
"data": [[1.25, 2, 3.5]],
"anns_field": "vector",
"param": {"metric_type": "COSINE"},
"limit": 100
}

req_dense = AnnSearchRequest(**search_params_dense)

search_params_sparse = {
"data": ["shoes"],
"anns_field": "text_sparse",
"param": {"metric_type": "BM25"},
"limit": 100
}

req_sparse = AnnSearchRequest(**search_params_sparse)

res = client.hybrid_search(
collection_name="my_collection",
reqs=[req_dense, req_sparse],
ranker=RRFRanker(),
limit=10
)

この例では、次を組み合わせた Milvus のハイブリッド検索を示します。

  1. 密ベクトル検索: vector フィールドに対する近似最近傍(ANN)検索に内積(IP)メトリクスを使用します。

  2. スパースベクトル検索: text_sparse フィールドに BM25 類似度メトリクスを使用します。

これらの検索の結果は個別に実行され、統合され、Reciprocal Rank Fusion(RRF)ランカーを使用して再ランク付けされます。ハイブリッド検索は、再ランク付けされたリストから上位 10 件のエンティティを返します。

標準的なテキストベースのクエリと kNN 検索の結果を統合する Elasticsearch の RRF ランキングとは異なり、Milvus はスパースベクトル検索と密ベクトル検索の結果を組み合わせ、マルチモーダルデータに最適化された独自のハイブリッド検索機能を提供します。

まとめ​

この記事では、タームレベルクエリ、Boolean クエリ、全文クエリ、ベクトルクエリなど、代表的な Elasticsearch クエリを Milvus の等価な機能に変換する方法について説明しました。他の Elasticsearch クエリの変換についてさらに質問がある場合は、お気軽にお問い合わせください。