1つのエンティティ、複数のベクトル: Milvus 3.0 StructArrayによるエンティティレベルおよび要素レベルの検索
ほとんどのベクターデータベースのスキーマは、単純な前提から始まります。つまり、1つのエンティティに1つの埋め込みという前提です。製品には1つのベクトルが対応し、ドキュメントにも同様に1つのベクトルが対応します。ユーザークエリは埋め込みベクトルに変換され、近似最近傍(ANN)検索によってこれらのベクトルと比較されます。このモデルは、RAG、セマンティック検索、レコメンデーションシステムなど、第一世代のベクター検索ユースケースで機能します。
しかし、実際のAIデータがこの前提に適合することはほとんどありません。動画にはクリップ、ショット、キーフレームが含まれ、それぞれに独自の埋め込み、時間範囲、キャプション、シーンラベル、信頼度スコアがあります。製品には複数の画像や視野角が含まれる場合があります。長いドキュメントには、ドキュメント全体の単一の埋め込みよりも局所的な意味が重要なパッセージやセクションが含まれます。一般的な後期相互作用モデルは、さらに細かい粒度で同じ制限を露呈します。ColBERTはトークンごとに1つのベクトルを生成し、ColPaliは視覚パッチごとに1つのベクトルを生成します。
どの場合も、親エンティティはアプリケーションが保存、表示、保護、返却する単位であり続けます。しかし、関連性、フィルタリング、結果の説明は、多くの場合、そのエンティティ内の要素に依存します。
新しいStructArray機能は、この形状に対するネイティブなデータモデルをMilvusに提供します。1つのエンティティに、スキーマ定義されたStruct要素の順序付き配列が含まれ、各要素はスカラーメタデータ、ベクター埋め込み、またはその両方を保持できます。Milvusは、同じ要素に属するフィールドをフィルタリングしたり、エンティティレベルで2つの埋め込みリストを比較したり、個々の要素を検索して一致するオフセットを返したりできます。
この記事では、動画検索の例を使用してデータモデルを説明し、スキーマ設計、フィルタリング、ベクター検索の粒度、EmbeddingListインデックス戦略、ハイブリッド結果のコラプス、この機能を実行可能にする物理レイアウトまでを順に追っていきます。
1つのベクトルと1つのフラット行モデルではもはや不十分な理由
ユーザーが動画カタログで「キッチンで野菜を切っている人物」を検索する場合を考えてみましょう。関連するシグナルは、動画全体の埋め込みではなく、8秒のクリップ1つに存在する可能性があります。すべてのクリップ、オブジェクト、アクションを単一のベクトルに圧縮すると、大まかなトピックは保持されるかもしれませんが、局所的な詳細が失われる可能性があります。
同じ不一致は他のワークロードでも発生します:
- 製品の関連性は、複数の画像や角度のうちの1つに由来する場合があります。
- ドキュメントは、全体的な主題ではなく、1つのパッセージによって一致する場合があります。
- エージェントのメモリには複数の観察結果が含まれる場合があり、そのうち現在のタスクに関係するのは1つだけの場合があります。
- ColBERTまたはColPaliのレコードには、単一の高密度ベクトルではなく、可変長のトークンまたはパッチベクトルのリストが含まれます。
1つの代替案は、すべてのクリップ、画像、パッセージを個別のデータベース行に分割することです。これにより局所検索が可能になりますが、各フラグメントが親エンティティから分離されます。親メタデータは行間で繰り返される可能性があり、エンティティレベルの検索には、フラグメント検索後のグループ化、重複排除、再ランキングが必要になります。
ネストされたストレージだけではクエリの問題は解決しません。JSONはオブジェクトを保存できますが、ベクターおよびスカラーインデックスのための事前定義されたサブフィールドスキーマをMilvusに提供しません。並列配列はキャプション、シーンラベル、信頼度値を保存できますが、アプリケーションがオフセットの整合性を維持する必要があります。データベースは、scene_type[3]とlabel_confidence[3]が同じクリップを記述していることを、その関係がデータモデルの一部でない限り安全に推論できません。
StructArrayはこの関係を直接エンコードします。親エンティティ内にローカル要素を保持しながら、整列されたサブフィールドをスキーマ検証、インデックス作成、フィルタリング、ベクター検索に公開します。
StructArrayとそのデータモデルとは?
StructArrayは、構造体の配列とも呼ばれ、各エンティティにStruct要素の順序付きセットを格納します。StructArrayフィールドは、すべての要素が1つの事前定義されたStructスキーマに従うArrayです。動画コレクションの場合、論理的な形状は次のようになります:
Plaintext
clips: ARRAY<STRUCT<
clip_embedding_list: FLOAT_VECTOR,
clip_embedding: FLOAT_VECTOR,
start_sec: DOUBLE,
end_sec: DOUBLE,
caption: VARCHAR,
scene_type: VARCHAR,
label_confidence: FLOAT
>>
ここで:
clipsは親のStructArrayフィールドです。clip_embedding_list、clip_embedding、start_sec、およびその他の属性はサブフィールドです。clips[0]は最初のクリップです。- オフセット
0のすべてのサブフィールドは、その同じクリップに属します。 - オフセット
3のすべてのサブフィールドは、別のクリップに属します。
2つのベクターサブフィールドは異なる検索モードを提供します。clips[clip_embedding_list]はエンティティレベルのEmbeddingList検索用にMAX_SIM*メトリックでインデックス作成され、clips[clip_embedding]は要素レベルの検索用に通常のベクターメトリックでインデックス作成されます。ベクターフィールドまたはベクターサブフィールドは1つのインデックスのみを受け入れるため、両方のモードが必要なコレクションは、2つのサブフィールドを個別に定義してインデックス作成する必要があります。
このモデルは3つの異なるクエリセマンティクスをサポートします。
1. EmbeddingList検索は親エンティティを返す
clips[clip_embedding_list]内のベクトルは、動画の1つの埋め込みリストを形成します。クエリもEmbeddingListです。MilvusはMAX_SIM*メトリックを使用してクエリリストを各保存済みリストと比較し、エンティティレベルの結果を返します。
Plaintext
clips[clip_embedding_list] = [
embedding_0,
embedding_1,
embedding_2,
...
]
2. MATCH_*ファミリーは親エンティティをフィルタリングする
MATCH_ANY、MATCH_ALL、MATCH_LEAST、MATCH_MOST、MATCH_EXACTは、Struct要素に対して述語を評価し、それを満たす要素の数をカウントし、親エンティティがフィルターを通過するかどうかを決定します。
たとえば:
Plaintext
MATCH_ANY(clips, $[scene_type] == "kitchen" && $[label_confidence] > 0.8)
両方のスカラー条件が同じクリップオフセットで真である必要があります。Milvusは、あるクリップのキッチンラベルと別のクリップの高信頼度値を組み合わせることはありません。
3. 要素レベルの検索は一致する要素オフセットを返す
通常のクエリベクトルは、clips[clip_embedding]内のすべてのベクトルを独立して検索できます。各ヒットは、親エンティティと一致するStruct要素のゼロベースのオフセットを識別します。element_filterを使用すると、そのベクター検索に参加する要素を制限できます。
これらの操作には共通の前提があります。Milvusは、どのベクター値とスカラー値が同じ要素に属し、どの要素が同じエンティティに属するかを把握しているということです。
StructArrayは汎用の任意ネストシステムではありません。現在のモデルは、サポートされているスカラーおよびベクターサブフィールドを持つStruct要素の1つのArrayです。この境界により、サブフィールドのインデックス作成と要素を認識した実行が実現可能になります。
スキーマ、インデックス、挿入パスの構築
次の簡略化されたPyMilvusの例では、1つのトップレベルベクトルとクリップ用のStructArrayを持つ動画コレクションを作成します。同じコレクションで両方の検索モードを実演できるように、個別のクリップベクターサブフィールドを使用しています。
from pymilvus import DataType, MilvusClient
client = MilvusClient(uri=“http://localhost:19530”)
schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field(“id”, DataType.INT64, is_primary=True)
schema.add_field(“title”, DataType.VARCHAR, max_length=512)
schema.add_field(“video_embedding”, DataType.FLOAT_VECTOR, dim=768)
# Define the Struct schema explicitly.
clip_schema = client.create_struct_field_schema()
clip_schema.add_field(“clip_embedding_list”, DataType.FLOAT_VECTOR, dim=768)
clip_schema.add_field(“clip_embedding”, DataType.FLOAT_VECTOR, dim=768)
clip_schema.add_field(“start_sec”, DataType.DOUBLE)
clip_schema.add_field(“end_sec”, DataType.DOUBLE)
clip_schema.add_field(“caption”, DataType.VARCHAR, max_length=2048)
clip_schema.add_field(“scene_type”, DataType.VARCHAR, max_length=128)
clip_schema.add_field(“label_confidence”, DataType.FLOAT)
schema.add_field(
“clips”,
datatype=DataType.ARRAY,
element_type=DataType.STRUCT,
struct_schema=clip_schema,
max_capacity=1024,
)
client.create_collection(“videos”, schema=schema)
ベクターサブフィールドは検索前にインデックス作成する必要があります。メトリックファミリーが検索モードを決定するため、各ベクターサブフィールドには独自のインデックスが設定されます:
index_params = client.prepare_index_params()
# EmbeddingList search.
index_params.add_index(
field_name="clips[clip_embedding_list]",
index_type=“HNSW”,
metric_type=“MAX_SIM_COSINE”,
index_name=“clips_clip_embedding_list_maxsim_idx”,
params={“M”: 16, “efConstruction”: 200},
)
# Element-level search.
index_params.add_index(
field_name="clips[clip_embedding]",
index_type=“HNSW”,
metric_type=“COSINE”,
index_name=“clips_clip_embedding_cosine_idx”,
params={“M”: 16, “efConstruction”: 200},
)
client.create_index(“videos”, index_params=index_params)
スカラーインデックスはオプションですが、大規模なフィルターで頻繁に使用されるサブフィールドには、互換性のあるスカラーインデックスを使用する必要があります。たとえば、clips[scene_type]は転置インデックスを使用でき、clips[label_confidence]などの数値サブフィールドは数値フィルタリングに適したインデックスを使用できます。
データは自然なエンティティ形状で挿入します。クリップオブジェクトの配列を持つ1つの動画行です。例をコンパクトに保つため、同じクリップベクトルを両方のベクターサブフィールドに書き込みます。
rows = [
{
"id": 1,
"title": "cooking tutorial",
"video_embedding": video_vec,
"clips": [
{
"clip_embedding_list": clip_vec_1,
"clip_embedding": clip_vec_1,
"start_sec": 0.0,
"end_sec": 8.0,
"caption": "A person washes vegetables.",
"scene_type": "kitchen",
"label_confidence": 0.92,
},
{
"clip_embedding_list": clip_vec_2,
"clip_embedding": clip_vec_2,
"start_sec": 8.0,
"end_sec": 16.0,
"caption": "A person cuts carrots on a board.",
"scene_type": "kitchen",
"label_confidence": 0.96,
},
],
}
]
client.insert(“videos”, rows)
client.flush(“videos”)
client.load_collection(“videos”)
API境界では、clipsは構造化オブジェクトの配列のままです。Milvus内部では、各サブフィールドは独自のインデックス、フィルター、出力動作に必要な型付きパスに従います。この区別は挿入時には透過的ですが、その後のすべての処理の基本となります。
同一要素フィルタリングが構造と並列配列の違いを生む
フィルタリングの主な利点は、ネストされたフィールドの構文が短くなることではありません。スカラーサブフィールド間の正しい相関関係を維持できることです。
アプリケーションが、ラベル信頼度が0.8を超えるキッチンのクリップを含む動画を必要としているとします。動画に何らかのキッチンのクリップと何らかの高信頼度のクリップが含まれているだけでは不十分で、同じクリップが両方の条件を満たす必要があります。
StructArrayのMATCH_*ファミリーはこれを直接表現します:
Plaintext
MATCH_ANY(clips, $[scene_type] == "kitchen" && $[label_confidence] > 0.8)
MATCH_ALL(clips, $[label_confidence] > 0.5)
MATCH_LEAST(clips, $[scene_type] == "sports", threshold=3)
MATCH_MOST(clips, $[label_confidence] < 0.2, threshold=1)
MATCH_EXACT(clips, $[scene_type] == "intro", threshold=1)
Milvusは各要素オフセットで述語を評価し、演算子の数量詞を適用して親エンティティが通過するかどうかを決定します:
MATCH_ANY:少なくとも1つの要素が一致します。MATCH_ALL:すべての要素が一致します。MATCH_LEAST:少なくともthreshold個の要素が一致します。MATCH_MOST:最大でthreshold個の要素が一致します。MATCH_EXACT:ちょうどthreshold個の要素が一致します。
同じデータが2つの独立した配列として保存されている場合、次の式はその相関関係を維持しません:
Plaintext
array_contains(clips[scene_type], "kitchen")
AND
array_contains(clips[label_confidence], 0.9)
2つの値は異なるオフセットで発生する可能性があります。これは無関係な属性では有効かもしれませんが、両方の条件が同じクリップ、製品画像、またはドキュメントのパッセージを記述している場合は正しくありません。
StructArrayは、要素の同一性をアプリケーションが強制する必要のある規約ではなく、データベース述語の一部にします。
2つのベクター検索の粒度、2つの結果の同一性
エンティティが複数のベクトルを格納すると、ANN検索が始まる前に、検索はモデリング上の問いに答える必要があります:
ベクトルは親エンティティの1つの表現として一緒にスコアリングされるべきでしょうか、それとも各要素ベクトルが独立して競合するべきでしょうか?
StructArrayは両方のモデルをサポートしますが、これらは異なるクエリ形状、メトリックファミリー、ベクターサブフィールド、結果の同一性を使用します。
EmbeddingList検索:クエリベクトルのリストがエンティティを見つける
EmbeddingListクエリには複数のベクトルが含まれます。クエリ動画は複数のクリップに分割される場合があります。製品クエリには複数の参照画像が含まれる場合があります。ColBERTクエリにはクエリトークンごとに1つのベクトルが含まれます。
各エンティティについて、Milvusはクエリリストをエンティティの保存済み埋め込みリストと比較します。MaxSimスタイルのスコアリングでは、各クエリベクトルがエンティティリスト内の最良の一致を選択し、Milvusはこれらの最良一致スコアを集約してエンティティスコアを算出します。最終的なヒットは、特定のStruct要素ではなく、親エンティティを表します。
from pymilvus.client.embedding_list import EmbeddingList
query = EmbeddingList()
query.add(query_clip_vec_1)
query.add(query_clip_vec_2)
client.search(
collection_name=“videos”,
data=[query],
anns_field="clips[clip_embedding_list]",
search_params={“metric_type”: “MAX_SIM_COSINE”},
limit=10,
)
この検索は次の問いに答えます:このクエリクリップのセットに対して、どの動画が全体的に最良の一致でしょうか?
これは、動画間検索、複数画像の製品検索、ColBERTおよびColPaliスタイルの検索、クエリと保存済みエンティティの両方が複数のベクトルで表現されるその他のケースに適しています。
要素レベルの検索:1つのクエリベクトルがエンティティ内のクリップを見つける
要素レベルの検索では、通常のクエリベクトルを使用します。clips[clip_embedding]内のすべてのベクトルが、独立した候補としてANN検索に参加します。各ヒットは、親エンティティと一致する要素のオフセットを識別します。
client.search(
collection_name="videos",
data=[query_vec],
anns_field="clips[clip_embedding]",
search_params={"metric_type": "COSINE"},
limit=10,
output_fields=["id", "title", "clips"],
)
選択したクリップのみを検索するには、スカラー条件が同じクリップに適用されるelement_filterをアタッチします:
client.search(
collection_name="videos",
data=[query_vec],
anns_field="clips[clip_embedding]",
search_params={"metric_type": "COSINE"},
filter='element_filter(clips, $[scene_type] == "kitchen" && $[label_confidence] > 0.8)',
limit=10,
output_fields=["id", "title", "clips"],
)
このフィルターは、最初にキッチンのクリップを選択してから、別の高信頼度クリップを検索するものではありません。両方の述語とベクター候補は同じStruct要素を参照します。
グループ化されていないレスポンスは次のようになります:
Plaintext
id = 1, offset = 1, distance = 0.91
id = 8, offset = 4, distance = 0.88
id = 1, offset = 3, distance = 0.84
複数のクリップが一致する可能性があるため、同じエンティティが複数回出現することがあります。これは、アプリケーションがどの動画またはドキュメントが関連するかだけでなく、どのクリップまたはパッセージが一致を生み出したかを表示する必要がある場合に役立ちます。
| 側面 | EmbeddingList検索 | 要素レベルの検索 |
|---|---|---|
| クエリ入力 | EmbeddingList内の1つ以上のクエリベクトル | 1つの通常のクエリベクトル |
| 対象の例 | clips[clip_embedding_list] | clips[clip_embedding] |
| メトリックファミリー | MAX_SIM* | COSINE、IP、L2などの通常のメトリック |
| ANN候補単位 | 親エンティティの埋め込みリスト | 各Struct要素ベクトル |
| 結果の同一性 | 親エンティティ | 親エンティティと要素オフセット |
| 典型的なユースケース | マルチベクタークエリをマルチベクターエンティティと一致させる | 最も関連性の高いクリップ、画像、パッセージ、パッチ、またはファクトを見つける |
1つのコレクションで両方のモードをサポートするには、個別のベクターサブフィールドを定義してインデックス作成します。クエリ形状、メトリックファミリー、対象インデックスが一致している必要があります。
EmbeddingListインデックスは品質とコストの選択
エンティティごとに1つの埋め込みがある場合、ANNインデックスはクエリベクトルに近いエンティティを見つけます。EmbeddingList検索は、関連性が2つのベクトルリスト間のペアごとの相互作用に依存するため、よりコストがかかります。
すべてのエンティティ内のすべてのベクトルに対して正確なMaxSimを計算すると、最もクリーンな参照ランキングが得られますが、フルスキャンは通常、オンライン検索にはコストがかかりすぎます。そのためMilvusは2段階モデルを使用します:
- 近似戦略が候補の親エンティティを取得します。
emb_list_rerankが有効な場合、Milvusはこれらの候補に対してMaxSimを再計算して最終的なランキングを生成します。
より多くの第1段階の候補を取得すると、真の上位結果が再ランカーに到達する可能性が一般的に高まりますが、レイテンシと計算量も増加します。3つの戦略は、主にこの候補セットの生成方法が異なります。
| 戦略 | 第1段階の候補表現 | 適しているケース | 主なトレードオフ |
|---|---|---|---|
| TokenANN | 各埋め込みリスト内のすべてのベクトルをインデックス作成します。クエリベクトルは独立してANNを実行し、一致はMaxSim再ランキングの前に親エンティティに集約されます。 | 品質が最優先で、リストが短いまたは中程度で、個々のベクトルが識別力を持つ場合。 | インデックスサイズと第1段階の検索作業は、リストの長さとクエリベクトルの数に応じて増加します。 |
| MUVERA | ランダム射影を使用して各埋め込みリストを1つの固定次元ベクトルにエンコードし、通常のANNを実行します。 | TokenANNが重すぎる場合、またはトレーニングパイプラインなしでの圧縮が望ましい場合。 | エンコードは情報を失います。より強い射影設定は、エンコードされた次元とANNコストを増加させます。 |
| LEMUR | 埋め込みリストを固定次元の親エンティティベクトルにマッピングするモデルをトレーニングします。 | 埋め込みの識別力が低い、リストが大きい、またはワークロードがビジュアルまたはマルチモーダルである場合。 | トレーニングが必要で、コーパスの分布やドキュメントの長さの偏りに敏感な場合があります。 |
すべてのワークロードに最適な単一の戦略はありません。対象データとクエリ分布から始めましょう:
- データセットサイズが許せば、品質優先のベースラインとしてTokenANNを使用します。
- リストの長さが増加するにつれてTokenANNのインデックスまたは候補検索がコスト高になる場合、またはトレーニングパイプラインを避けたい場合は、MUVERAを試します。
- 埋め込み空間がノイズが多い、または識別力が弱い場合、またはワークロードがビジュアルまたはマルチモーダルである場合は、LEMURを評価します。
- レイテンシとインデックスサイズとともに、再現率またはnDCGを測定します。短いテキストで機能する戦略でも、ロングテールのドキュメント長や数千のビジュアルパッチでは異なる動作をする可能性があります。
StructArrayは1つの問題に対処します。単一のエンティティ内で整列された、フィルタリング可能な、ベクターを持つ要素を表現する方法です。EmbeddingList戦略は別の問題に対処します。特定のモデルとコーパスに対して許容可能なコストでMaxSimを近似する方法です。
ハイブリッド検索が結果の同一性を明確にする
本番環境の検索が単一のベクターパスに従うことはほとんどありません。動画リクエストは、トップレベルの動画埋め込み、1つ以上のクリップレベルの埋め込み、キャプションや文字起こしのシグナル、再ランカーを組み合わせる場合があります。
要素レベルの候補がこのパイプラインに入ると、エンジンは最終候補を何で識別するかを決定する必要があります。
| ハイブリッドリクエストの構成 | 最終候補のスコープ | 結果の同一性 |
|---|---|---|
| すべてのサブ検索が要素レベルで、同じStructArrayの下のベクターサブフィールドを対象とする | 要素レベル | 主キーとStructArrayフィールドと要素オフセット |
| トップレベルのベクターフィールドが含まれる | エンティティレベル | 主キー |
| EmbeddingListリクエストが含まれる | エンティティレベル | 主キー |
| 要素レベルのリクエストが異なるStructArrayフィールドを対象とする | エンティティレベル | 主キー |
最初の構成は要素の同一性を維持します。オフセット3が、特定の親StructArrayの下のすべてのサブ検索で同じStruct要素を参照するためです。これは、複数の要素レベルのシグナルを融合した後に最も関連性の高いクリップまたはパッセージを返したいアプリケーションに適しています。
他の構成では、候補の粒度または要素の名前空間が混在します。そのため、要素ヒットは最終的な再ランキングの前にエンティティレベルのスコアにコラプスする必要があります。Milvusはいくつかのコラプス戦略をサポートします:
| コラプス戦略 | 返された要素ヒットからのエンティティスコア | 重要な条件 |
|---|---|---|
max | 最良の要素スコア | サポートされている通常のベクターメトリックで動作 |
sum | 返されたすべての要素スコアの合計 | IPやCOSINEなどの正の相関メトリックで使用 |
avg | 返された要素スコアの平均 | サポートされている通常のベクターメトリックで動作 |
topk_sum | 返された要素スコアの最良K個の合計 | 正のtopkが必要。IPまたはCOSINEで使用 |
topk_avg | 返された要素スコアの最良K個の平均 | 正のtopkが必要 |
コラプスは、そのANNサブ検索によって返された要素ヒットに対してのみ動作し、検索後にエンティティ内のすべての要素をスキャンするわけではありません。したがって、リクエストのlimitが、コラプス関数で使用できる要素ヒットを制御します。
この選択は、単なる出力フォーマットではなく、検索セマンティクスを形成します。アプリケーションがクリップやパッセージを表示する場合、融合を通じてオフセットを維持することが自然です。動画、製品、またはドキュメントを表示する場合は、エンティティレベルのコラプスが自然です。シグナルが異なる粒度で動作する場合、システムには明示的な要素からエンティティへのスコアリングルールが必要です。
StructArrayは、この同一性とコラプスの問題を、アドホックな後処理から検索実行モデルに移します。
MilvusがStructArrayをブロブとして扱わずに実行する仕組み
ユーザー向けのモデルはARRAY<STRUCT>です。しかし、値全体を単一の不透明なブロブとして保存すると、サブフィールドのインデックス、フィルター、選択的な出力が非効率になります。
Milvusは、論理的な親、物理的な子カラムの設計を使用します。
スキーマ層では、clipsが論理的な親フィールドです。Structスキーマ、最大容量、NULL許容性などのプロパティを定義します。そのサブフィールドは、clips[clip_embedding_list]、clips[clip_embedding]、clips[scene_type]、clips[label_confidence]などのパスに正規化されます。
スカラーサブフィールドはエンティティごとにスカラー配列のストレージパスに従い、ベクターサブフィールドはベクター配列のパスに従います。各サブフィールドは、そのタイプに適したデータパスを使用できます。メタデータにはスカラーフィルタリングとスカラーインデックス、埋め込みにはベクターインデックスとANN検索です。
取り込み時に、ProxyはネストされたStructリストを型付きの子カラムに展開します。実行中、Milvusは各物理要素とその親エンティティの関係を維持します。概念的には、この関係は次のようになります:
Plaintext
entity 0 -> elements [0, 1, 2]
entity 1 -> elements [3]
entity 2 -> elements []
entity 3 -> elements [4, 5, 6, 7]
要素レベルの検索が物理要素IDを返すと、Milvusはそれを親エンティティと要素オフセットにマッピングします。element_filterが要素レベルのビットマップを生成すると、エンジンはそれを親エンティティの可視性、削除、その他のフィルターと整列させます。
結果を返すとき、Milvusは論理スキーマと共有オフセットを使用して、アプリケーションが挿入したStructArray形状を再構築します。システムは型付きの子カラム上で実行できますが、ユーザーは自然なネストされたオブジェクトの読み書きを継続できます。この物理レイアウトにより、StructArrayは型付きJSON以上のものになります。ネストされた関係がインデックスと実行モデルに参加します。
StructArrayが適しているケースと適していないケース
StructArrayは、以下のすべてが当てはまる場合に最適です:
- アプリケーションに、動画、製品、ドキュメント、ビジュアルページ、メモリレコードなどの意味のある親エンティティがある。
- 各親に、順序付きの可変長のローカル要素セットが含まれている。
- それらの要素に独自のスカラーメタデータ、ベクトル、またはその両方が必要である。
- 検索またはフィルタリングが、同じ要素オフセットのサブフィールド間の関係を維持する必要がある。
- アプリケーションにエンティティレベルのマルチベクター検索、要素レベルのヒット、またはその両方が必要である。
StructArrayがすべてのコレクションで自動的に優れているわけではありません。短いドキュメントや単純なクエリは、単一の高密度埋め込みで十分に対応できる場合があります。マルチベクターインデックスはストレージと検索のコストを追加するため、追加の表現は、検索品質の向上またはより有用な結果の粒度によってその価値を証明する必要があります。
現在のスキーマと実行の境界も重要です:
Structは、Arrayの要素タイプとしてサポートされており、トップレベルのコレクションフィールドとしてはサポートされていません。- 1つのStructArray内のすべての要素は、1つの事前定義されたスキーマを共有します。
max_capacityは必須で、エンティティごとの要素数を制限します。- ネストされた
Struct、Array、ArrayOfStruct、JSONサブフィールドはStructArray内ではサポートされていません。 - ベクターサブフィールドは1つのインデックスを受け入れます。両方が必要な場合は、EmbeddingListと要素レベルの検索に個別のベクターサブフィールドを使用します。
- ベクターサブフィールドは検索前にインデックス作成する必要があります。フィルターで頻繁に使用されるスカラーサブフィールドは、適切にインデックス作成する必要があります。
- サブフィールドスキーマはStructArrayフィールドの作成後に固定されるため、本番展開前に要素属性を計画してください。
これらの制約により、モデルはドキュメントデータベースの任意のネストよりも狭くなりますが、要素の同一性を推論し、各サブフィールドをインデックス作成し、2つの検索粒度で実行するための十分な構造をMilvusに提供します。
StructArrayはエンティティを失わずにローカルな証拠を第一級のものとして維持する
StructArrayは、フラットなスキーマでは表現が難しい検索オブジェクトをMilvusに提供します。それは、順序付きの構造化要素セットを持つ親エンティティです。これらの要素間の関係は、ストレージにのみ存在するのではなく、フィルタリング、インデックス作成、検索に参加します。
各要素は独自のメタデータと埋め込みを保持します。要素は、同じ要素のスカラー述語を満たしたり、エンティティレベルのEmbeddingList検索に一緒に参加したり、要素レベルの検索で独立して競合したりできます。同時に、それらはメタデータ、権限、アプリケーションの同一性がコンテキストを提供する親エンティティに接続されたままです。
ビデオクリップ、製品画像、ドキュメントのパッセージ、ビジュアルパッチ、メモリフラグメントについて、ローカルな証拠は、それが属するエンティティを失うことなく検索およびフィルタリングできます。残りの設計上の選択は明示的です。検索の粒度を選択し、各ベクターサブフィールドに一致するメトリックとインデックスを設定し、ハイブリッド結果が要素オフセットを維持するかエンティティにコラプスするかを決定します。
Milvus 3.0でStructArrayを試す
StructArrayはMilvus 3.0で利用可能です。StructArrayの概要から始めてください。エンティティレベルのマルチベクター検索を評価している場合は、EmbeddingList戦略ガイドをお読みください。結果の粒度とコラプス動作については、StructArrayを使用したハイブリッド検索を参照してください。
リリース全体の文脈については、Milvus 3.0ローンチブログ、リリースノート、milvus-io/milvusリポジトリを参照してください。
Zilliz Cloudも、マネージドデプロイメント向けにStructArrayとEmbeddingList検索をサポートしています。サービス固有の制限については、Zilliz CloudのStructArrayガイドを確認してください。Zilliz Cloudでは、StructArrayのスカラー演算子は現在、On-Demandクラスター向けにドキュメント化されています。
チームとスキーマや検索設計について議論するには、Milvus Discordコミュニティに参加するか、Milvus Office Hoursセッションを予約してください。
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



