メンバーシップ・マッチCompatible with Milvus v3.0.2+

概要

メンバーシップマッチは、スカラーフィールドの値が呼び出し元から提供された集合に属するかどうかを検証することで、エンティティをフィルタリングします。クライアントは、コンパクトなバイナリ形式のメンバーシップフィルタブロブを構築し、それを式テンプレートの値として渡します。

これは、大規模なIN [...] リストに代わるものです。IN フィルターは、すべてのメンバーをリクエストにシリアライズするため、メンバーセットが十分に大きい場合、プロキシのgRPC受信制限を超える可能性があります。membership_match を使用すると、プロキシはblobを検証し、メンバーリストを再構築することなくクエリプランに埋め込みます。

Membership Match workflow: the client builds a reusable blob, the proxy validates it, and QueryNodes evaluate it. メンバーシップ・マッチのワークフロー:クライアントが再利用可能なblobを構築し、プロキシがそれを検証し、QueryNodesがそれを評価します。

この図は、固定された役割分担を示しています。クライアントは Blob を一度構築してリクエスト間で再利用し、プロキシはエンベロープとサイズ制限を検証して Blob をそのままクエリプランに埋め込み、QueryNodes は生データまたはインデックスに対してそのプランを評価します。

この演算子には、正確性の保証レベルが異なる 2 種類のエンコーディングがあります:

  • Bloom(type=bloom): 近似メンバーシップ。偽陽性が発生する可能性がありますが、有効なフィルタでは偽陰性は想定されません。代表的な用途:大量のオーディエンスや除外フィルタで、時折の偽陽性が許容される場合。
  • Roaring(type=roaring): 整数値に対する厳密なメンバーシップ判定。代表的な用途:ACL、テナントの可視性、コンプライアンス・フィルター、および ID セットによる削除操作。

認証の決定や破壊的な削除には、ブルームメンバーシップを使用しないでください。誤検知が発生すると、意図したセットに含まれていないエンティティが公開されたり、削除されたりする可能性があります。

運用チェックリスト

  • 対象フィールドの型を確認し、その値のドメインに基づいてBLOBを構築してください。
  • 誤検知が許容できる場合にのみ、ブルームを選択してください。
  • ACL、コンプライアンス、テナントの分離、および削除操作には「Roaring」を選択してください。
  • 大きな Blob は一度生成して再利用し、リクエストごとに再生成しないでください。
  • Blobのサイズは、メンバー数ではなく、シリアライズされたバイト数で予算を立てる。
  • バージョンが混在するクラスターでは、membership_match を有効にする前に、プロキシから順にローリングアップグレードを完了させてください。
  • 破壊的なワークフローを有効にする前に、本番環境以外のコレクションで式をテストしてください。

式の構文

membership_match(<field>, {<template>}, type=bloom)
membership_match(<field>, {<template>}, type=roaring)
membership_match(<field>, {<template>})
not membership_match(<field>, {<template>}, type=bloom)

2 番目の引数はテンプレートのプレースホルダーです。SDK は、クライアントが構築したフィルター Blob を含む protobufbytes として、プレースホルダーの値を提供します。本番環境の式では、type を明示的に指定し、意図した正しさの契約がコードやログで確認できるようにしてください。

type 引数はオプションです。すべてのブロブには自己記述型のマジックヘッダー(Bloomの場合はMBF1 、Roaringの場合はMRB1 )が含まれており、type が省略された場合、サーバーはこのヘッダーを検知します。ブロブのヘッダーと競合する明示的なtype はリクエストエラーとして拒否され、不明または切り詰められたヘッダーはfail-closed状態となります。

エンコーディングの選択

誤検知(false positive)が許容できる場合は、Bloomを使用してください。Bloomは、符号付き整数フィールド(INT8/16/32/64)、VARCHARフィールド、およびJSONパスを受け入れます。Bloomフィルタは厳密な許可リストではありません。

fpr (偽陽性率)とは、値が一度も挿入されていないにもかかわらず、Bloomフィルタがその値をメンバーとして報告する確率のことです。fpr=0.005 の場合、およそ200個に1個の非メンバー値が、誤って存在すると報告されることを意味します。fprが低いほど、Blobのサイズが大きくなります。

すべての一致が完全一致でなければならない場合は、Roaringを使用してください。Roaringは符号付き整数フィールドのみを受け付けます。メンバーはシリアライズ前にINT64に符号拡張されるため、INT8の-1とINT64の-1は同じメンバーとなります。UUIDやその他の文字列フィールドには使用しないでください。

ディメンションBloom (type=bloom)Roaring (type=roaring)
精度近似;偽陽性の可能性あり;偽陰性なし正確;偽陽性および偽陰性なし
フィールドINT8/16/32/64、VARCHAR、JSONパス符号付き INT8/16/32/64 のみ
BLOB サイズメンバー数と FPR。FPR 0.005 の場合、メンバー 1 つあたり約 11 ビット。本体は 2 の冪値の分布。密度の高い集合ははるかに小さなサイズに圧縮される。ランダムな 64 ビットの値は、コンテナの上限である 262,144 に達する
削除解析時に拒否される許可
代表的な用途対象および除外フィルターACL、コンプライアンス、テナントの分離、IDセットによる削除

JSONパスは、行ごとに厳密に型指定されます。JSON文字列はVARCHAR値として、JSON整数はINT64値として検査され、JSON倍精度浮動小数点は整数メンバーと一致することはありません。これは、5.0 が 5. に等しい厳密なIN とは異なります。 ライターが整数を浮動小数点形式でエンコードする場合は、書き込み時に正規化するか、型付きスカラーフィールドを使用してください。

どちらのエンコーディングの場合も、ターゲットフィールドと同じ値ドメインからメンバセットを構築してください。 文字列"10086" からブルームフィルタを構築し、それをINT64 フィールドに適用しないでください。BLOB ヘッダーには挿入された値のドメインが記録されており、ドメインが間違っている BLOB は、何も一致しないまま黙って処理されるのではなく、パラメータエラーとしてプロキシによって拒否されます。クエリごとに BLOB を再構築するのではなく、構築済みの BLOB をリクエスト間で再利用してください。

メンバー数が数千以下のセットについては、単純な `IN ` が依然として最も簡単な選択肢です。サーバーは`IN`、`Bloom`、`Roaring` のいずれかを選択することはありません。エンコーディングの選択は呼び出し側の責任です。

エンコーディングを選択するには:

  1. ワークロードが誤検知(false positive)を許容するかどうかを判断します。許容しない場合は、Bloomは選択肢になりません。
  2. 正確なメンバーシップが必要な場合は、符号付き整数フィールドを使用してRoaringを使用します。値が密集している場合やクラスタ化されている場合は、Blob が最小サイズに圧縮されます。
  3. サイズ制限を確認します。一様乱数による 64 ビット値は、コンテナの上限である 262,144 またはサイズ制限を超える可能性があります。その場合は、リクエストの制限内に収まる従来のINリストを使用してください。
  4. 整数以外のフィールドで厳密なメンバーシップを指定する場合は、INを使用してください。これらのフィールドには、厳密なメンバーシップのエンコーディングは存在しません。

メンバーシップの一致判定は、RESTful HTTP API では利用できません。HTTP 式テンプレートのパラメータは、bool、number、string、および array 値のみを受け付けます。blob 用のバイナリ型 `bytes ` は存在しません。メンバーシップ blob を渡すには、gRPC ベースの SDK を使用してください。

SDKのリクエストパターン

以下のスニペットは、メンバーシップ・ブロブの構築と、それらをフィルター・テンプレートのパラメータとして渡すことに焦点を当てています。これらは、コレクションとフィールドがすでに存在し読み込まれていること、SDKクライアントが接続されていること、およびクエリベクトル、メンバーリスト、その他の参照変数が定義されていることを前提としています。コレクションの設定およびアプリケーションの完全なスケルトン構築については省略しています。

from pymilvus import MilvusClient, build_bloom_filter, build_roaring_bitmap

client = MilvusClient(uri="http://localhost:19530")
bloom_blob = build_bloom_filter(["creator-a", "creator-b"], fpr=0.005)
client.search(collection_name="posts", data=[query_vector], anns_field="embedding", limit=10,
              filter="membership_match(creator_id, {members}, type=bloom)",
              filter_params={"members": bloom_blob})

roaring_blob = build_roaring_bitmap([1001, 1002, 1003])
client.query(collection_name="docs", filter="membership_match(user_id, {members}, type=roaring)",
             filter_params={"members": roaring_blob}, output_fields=["user_id", "title"])
bloomBlob, err := milvusclient.NewBloomFilterBlob([]int64{1001, 1002}, fpr)
if err != nil { return err }
search := milvusclient.NewSearchOption("posts", topK, vectors).
    WithFilter("membership_match(creator_id, {members}, type=bloom)").
    WithTemplateParam("members", bloomBlob)

roaringBlob, err := milvusclient.NewRoaringBitmapBlob([]int64{1001, 1002})
if err != nil { return err }
query := milvusclient.NewQueryOption("docs").
    WithFilter("membership_match(user_id, {members}, type=roaring)").
    WithTemplateParam("members", roaringBlob)
byte[] bloomBlob = BloomFilterUtils.buildBloomFilter(userIds, BloomFilterUtils.DEFAULT_FPR);
QueryReq request = QueryReq.builder().collectionName("docs")
    .filter("membership_match(user_id, {members}, type=bloom)")
    .filterTemplateValues(Collections.singletonMap("members", bloomBlob)).build();
byte[] roaringBlob = RoaringBitmapUtils.buildRoaringBitmap(userIds);
const bloomBlob = buildBloomFilter(userIds);
await client.query({ collection_name: 'docs',
  filter: 'membership_match(user_id, {members}, type=bloom)',
  exprValues: { members: bloomBlob } });
const roaringBlob = buildRoaringBitmap(integerIds);

Roaring を使用した削除

外部の整数IDセットで選択されたエンティティを削除する際は、厳密なRoaringBlobを使用してください。削除を実行する前に、メンバーセットとコレクションのフィールド型を確認してください。Bloomは使用しないでください。近似メンバーシップは安全な削除述語ではなく、Bloom形式は解析時にDelete式で拒否されます。

roaring_blob = build_roaring_bitmap([1001, 1002, 1003])
client.delete(collection_name="docs", filter="membership_match(id, {members}, type=roaring)",
              filter_params={"members": roaring_blob})
roaringBlob, err := milvusclient.NewRoaringBitmapBlob([]int64{1001, 1002, 1003})
if err != nil { return err }
_, err = client.Delete(ctx, milvusclient.NewDeleteOption("docs").
    WithExpr("membership_match(id, {members}, type=roaring)").
    WithTemplateParam("members", roaringBlob))
byte[] roaringBlob = RoaringBitmapUtils.buildRoaringBitmap(userIds);
DeleteReq request = DeleteReq.builder().collectionName("docs")
    .filter("membership_match(id, {members}, type=roaring)")
    .filterTemplateValues(Collections.singletonMap("members", roaringBlob)).build();
const roaringBlob = buildRoaringBitmap(integerIds);
await client.delete({ collection_name: 'docs',
  filter: 'membership_match(id, {members}, type=roaring)',
  exprValues: { members: roaringBlob } });

削除のセマンティクスは、厳密な三値マッチングに従います:

フィールド値membership_match(…)not membership_match(…)
NULL一致なし (NULL)一致なし (NULL)
メンバーセット内一致一致なし
集合外一致なし一致

この表は行ごとに次のように読み取れます。membership_match を含む Delete はセット内のエンティティを削除し、not membership_match を含む Delete はセット外のエンティティを削除し、NULL のエンティティはどちらの極性でも削除されません。

  • フィールド値が NULL のエンティティは、どちらの極性でも削除されることはありません。
  • 空のビットマップは何も削除しません。not membership_match(<field>, {<empty>}, type=roaring) は、フィールド値が NULL ではないすべてのエンティティを削除します。これは正確な補集合であり、設計上、大きな集合になる場合があります。
  • not membership_match これは、NULL ではないエンティティに対するメンバーセットの厳密な補集合であり、近似値ではありません。

インデックスのみが読み込まれ、生のスカラーデータがないシールドされたセグメントでは、インデックスがサポートしている場合、評価には境界付き逆引きが使用されます。生のフィールドデータも適格なインデックスも利用できない場合、リクエストはフィルタリングされていないエンティティを返すのではなく、FieldNotLoaded として失敗します。

操作上の制限

設定デフォルト設定可能制限対象
proxy.maxMembershipFilterSize64 MiBmilvus.yaml プロキシ1つのBlob本体
proxy.maxMembershipFilterPlanSize128 MiBmilvus.yaml プロキシリクエストごとの集計値
proxy.grpc.serverMaxRecvSize128 MiBmilvus.yaml プロキシリクエスト全体
Roaringのコンテナ上限262,144コード内で修正済みフィルターごと
Roaringのデコード済みメモリ推定値64 MiBコード内で固定フィルタごとに
MBF1 フォーマットの上限128 MiBコードで固定BLOB 形式の上限
ブルームfpr0.005クライアントビルダー偽陽性のターゲット

proxy.* の設定はMilvusサーバーの設定です。これらはクラスターオペレーターがmilvus.yaml のproxy セクションで設定するものであり、フィルタリング時にリクエストごとや式ごとに調整することはできません。Roaringadmissions および MBF1 フォーマットの上限は実装で固定されており、どこでも設定することはできません。fpr 行は、クライアント側で制御できる唯一の項目です。これは Blob の構築時に選択され、許容範囲は 0.0001 から 0.05 です。

Blob ボディの最大容量は、デフォルトの FPR において約 4,860 万個の INT64 メンバーを収容可能であり、その上に固定の 32 バイトのエンベロープヘッダーが追加されます。 リクエスト全体の予算は、メンバーを含むプランのシリアライズされた合計サイズと、Roaringフィルターのデコード後の推定合計サイズをカバーしており、HybridSearchのサブリクエストとスコアラーフィルターはこの予算を共有します。ブルーム・ボディのサイズは2の冪乗になります。つまり、メンバー数がティアの境界をわずかに超えるとBLOBのサイズは2倍になり、FPRをわずかに高く設定すれば、多くの場合、1つ下のティアに収まります。 プロキシがサイズ超過のブルームブロブを拒否した場合、エラーメッセージには、収まるfpr が示唆されます。

  • メンバーシップ式の結果は、リクエスト間でキャッシュされません。
  • バージョンが混在するクラスタでは、クエリが失敗します。古いコードを実行している QueryNode は、メンバーシップ・プラン・ノードを含むプランを拒否します。まずプロキシをアップグレードし、オペレーターを有効にする前にローリングアップグレードを完了させてください。
  • サーバーログでは、ブロブのバイトデータが伏せられます。式テキストにはテンプレート名のみが含まれ、バイナリペイロードはテンプレート値として帯域外で送信されます。

翻訳DeepL

マネージド Milvus を無料で試す

Zilliz Cloud は手間いらず、Milvus を基盤に 10 倍高速です。

始める
フィードバック

このページは役に立ちましたか ?