メインコンテンツまでスキップ
バージョン: User Guides (Cloud)

NGRAM
Public Preview

Zilliz CloudのNGRAMインデックスは、VARCHARフィールドまたはJSONフィールド内の特定のJSONパスのLIKEクエリを高速化するために構築されています。インデックスを構築する前に、Zilliz Cloudはテキストを固定長nの短い重複するサブストリングに分割します。これはn-gramとして知られています。例えば、n = 3の場合、単語「Milvus」は3-gramの「Mil」、「ilv」、「lvu」、および「vus」に分割されます。これらのn-gramは、各グラムをそのグラムが出現するドキュメントIDにマッピングする反転インデックスに格納されます。クエリ時には、このインデックスによりZilliz Cloudは検索を候補の少数に迅速に絞り込むことができ、はるかに高速なクエリ実行が可能になります。

以下のような高速なプレフィックス、サフィックス、インフィックス、またはワイルドカードフィルタリングが必要な場合に使用してください。

  • name LIKE "data%"

  • title LIKE "%vector%"

  • path LIKE "%json"

📘注意

フィルター式の構文の詳細については、基本的な演算子を参照してください。

仕組み

Zilliz Cloudは、NGRAMインデックスを2段階のプロセスで実装しています。

  1. インデックスの構築: 各ドキュメントのn-gramを生成し、インジェスト中に反転インデックスを構築します。

  2. クエリの高速化: インデックスを使用して少数の候補セットにフィルタリングし、その後正確な一致を検証します。

フェーズ1: インデックスの構築

データインジェスト中に、Zilliz CloudはNGRAMインデックスを構築するために以下の2つの主なステップを実行します。

  1. テキストをn-gramに分解する: Zilliz Cloudは、対象フィールド内の各文字列にnのウィンドウをスライドさせ、重複するサブストリング(n-gram)を抽出します。これらのサブストリングの長さは、設定可能な範囲[min_gram, max_gram]内にあります。

    • min_gram: 生成する最小のn-gram。また、インデックスの恩恵を受けることができる最小クエリ部分文字列長も定義します。

    • max_gram: 生成する最大のn-gram。クエリ時にも、長いクエリ文字列を分割する際の最大ウィンドウサイズとして使用されます。

    例えば、min_gram=2およびmax_gram=3の場合、文字列"AI database"は以下のように分解されます。

QZqlwniNDhE82ZbzE09cd7uHnWd

  • 2-grams: AI, I_, _d, da, at, ...

  • 3-grams: AI_, I_d, _da, dat, ata, ...

📘注意
  • 範囲[min_gram, max_gram]に対して、Zilliz Cloudは2つの値(両端を含む)の間のすべての長さについてn-gramを生成します。例えば、[2,4]と単語"text"の場合、Zilliz Cloudは以下を生成します。

  • 2-grams: te, ex, xt

  • 3-grams: tex, ext

  • 4-grams: text

  • N-gramの分解は文字ベースであり、言語に依存しません。例えば中国語では、"向量数据库"min_gram = 2)は"向量""量数""数据""据库"に分解されます。

  • スペースや句読点は分解中に文字として扱われます。

  • 分解では元のケースが維持され、一致は大文字小文字を区別します。例えば、"Database""database"は異なるn-gramを生成し、クエリ時に正確なケースマッチングが必要になります。

  1. 反転インデックスを構築する: 各生成されたn-gramを含むドキュメントIDのリストにマッピングする反転インデックスが作成されます。

    例えば、2-gram "AI"がIDが1、5、6、8、および9のドキュメントに出現する場合、インデックスは{"AI": [1, 5, 6, 8, 9]}を記録します。このインデックスはクエリ時に検索範囲を迅速に絞り込むために使用されます。

BVPlwaN7Lh7UZibGopwcAcYQn1d

📘注意

より広い[min_gram, max_gram]範囲は、より多くのグラムとより大きなマッピングリストを作成します。メモリが限られている場合は、非常に大きなポスティングリストにはmmapモードを検討してください。詳細については、mmapの使用を参照してください。

フェーズ2: クエリの高速化

LIKEフィルタが実行される際、Zilliz CloudはNGRAMインデックスを使用して以下の手順でクエリを高速化します。

XKwRwOPv6hqzpTb3ue8cbM8WnGe

  1. クエリ語の抽出: ワイルドカードを含まない連続した部分文字列がLIKE式から抽出されます(例:"%database%""database"になります)。

  2. クエリ語の分解: クエリ語はその長さ(L)とmin_gramおよびmax_gramの設定に基づいてn-gramに分解されます。

    • L < min_gramの場合、インデックスは使用できず、クエリは全スキャンにフォールバックします。

    • min_gram ≤ L ≤ max_gramの場合、クエリ語全体が単一のn-gramとして扱われ、これ以上の分解は不要です。

    • L > max_gramの場合、クエリ語はmax_gramに等しいウィンドウサイズを使用して重複するグラムに分解されます。

    例えば、max_gram3に設定され、クエリ語が長さ8"database"の場合、"dat""ata""tab"などの3-gramサブストリングに分解されます。

  3. 各グラムの検索と交差: Zilliz Cloudは反転インデックス内の各クエリグラムを検索し、結果のドキュメントIDリストを交差させて少数の候補ドキュメントを検索します。これらの候補はクエリのすべてのグラムを含みます。

  4. 検証と結果の返却: 元のLIKEフィルタが正確な一致を検索するために少数の候補セットのみに最終確認として適用されます。

NGRAMインデックスの作成

VARCHARフィールドまたはJSONフィールド内の特定のパスにNGRAMインデックスを作成できます。

例1: VARCHARフィールドでの作成

VARCHARフィールドでは、field_nameを指定し、min_grammax_gramを設定するだけです。

from pymilvus import MilvusClient

client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT") # サーバーアドレスに置き換えてください

# コレクションスキーマに"test"という名前のVARCHARフィールドを定義したと仮定します

# インデックスパラメータを準備
index_params = client.prepare_index_params()

# "text"フィールドにNGRAMインデックスを追加
index_params.add_index(
field_name="text", # 対象VARCHARフィールド
index_type="NGRAM", # インデックスタイプはNGRAM
index_name="ngram_index", # インデックスのカスタム名
min_gram=2, # 最小部分文字列長(例:2-gram: "st")
max_gram=3 # 最大部分文字列長(例:3-gram: "sta")
)

# コレクションにインデックスを作成
client.create_index(
collection_name="Documents",
index_params=index_params
)

この構成は、text内の各文字列に対して2-gramと3-gramを生成し、反転インデックスに格納します。

例2: JSONパスでの作成

JSONフィールドでは、グラム設定に加えて、以下のパラメータを指定する必要があります。

  • params.json_path – インデックス化する値を指すJSONパス。

  • params.json_cast_type"varchar"(大文字小文字を区別しない)である必要があります。NGRAMインデックスは文字列で動作します。

# コレクションスキーマに"json_field"という名前のJSONフィールドを定義し、"body"という名前のJSONパスがあると仮定します

# インデックスパラメータを準備
index_params = client.prepare_index_params()

# JSONフィールドにNGRAMインデックスを追加
index_params.add_index(
field_name="json_field", # 対象JSONフィールド
index_type="NGRAM", # インデックスタイプはNGRAM
index_name="json_ngram_index", # カスタムインデックス名
min_gram=2, # 最小n-gram長
max_gram=4, # 最大n-gram長
params={
"json_path": "json_field[\"body\"]", # JSONフィールド内の値へのパス
"json_cast_type": "varchar" # 必須: 値をvarcharにキャスト
}
)

# コレクションにインデックスを作成
client.create_index(
collection_name="Documents",
index_params=index_params
)

この例では:

  • json_field["body"]の値のみがインデックス化されます。

  • 値はn-gramトークナイズの前にVARCHARにキャストされます。

  • Zilliz Cloudは長さ2から4のサブストリングを生成し、反転インデックスに格納します。

JSONフィールドのインデックス作成の詳細については、JSONインデックスを参照してください。

NGRAMによって高速化されるクエリ

NGRAMインデックスが適用されるには:

  • クエリはNGRAMインデックスを持つVARCHARフィールド(またはJSONパス)を対象にする必要があります。

  • LIKEパターンのリテラル部分は少なくともmin_gram文字の長さである必要があります。 (例えば、最も短いクエリ語が2文字の場合、インデックス作成時にmin_gram=2を設定してください。)

サポートされているクエリタイプ:

  • プレフィックスマッチ

    # "database"で始まる任意の文字列にマッチ
    filter = 'text LIKE "database%"'
  • サフィックスマッチ

    # "database"で終わる任意の文字列にマッチ
    filter = 'text LIKE "%database"'
  • インフィックスマッチ

    # どこかに"database"という部分文字列を含む任意の文字列にマッチ
    filter = 'text LIKE "%database%"'
  • ワイルドカードマッチ

    Zilliz Cloudは%(0文字以上)と_(正確に1文字)の両方をサポートしています。

    # "st"が最初に出現し、その後に"text"内に"um"が出現する任意の文字列にマッチ
    filter = 'text LIKE "%st%um%"'
  • JSONパスクエリ

    filter = 'json_field["body"] LIKE "%database%"'

フィルター式の構文の詳細については、基本的な演算子を参照してください。

インデックスの削除

drop_index()メソッドを使用して、コレクションから既存のインデックスを削除します。

client.drop_index(
collection_name="Documents", # コレクション名
index_name="ngram_index" # 削除するインデックス名
)

使用上の注意

  • フィールドタイプ: VARCHARおよびJSONフィールドでサポートされています。JSONでは、params.json_pathparams.json_cast_type="varchar"の両方を指定してください。

  • Unicode: NGRAM分解は文字ベースであり、言語に依存せず、空白と句読点を含みます。

  • スペース・時間のトレードオフ: 広いグラム範囲[min_gram, max_gram]はより多くのグラムと大きなインデックスを生成します。メモリが限られている場合は、大きなポスティングリストにはmmapモードを検討してください。詳細については、mmapの使用を参照してください。

  • 不変性: min_grammax_gramはインプレースでは変更できません。調整するにはインデックスを再構築してください。

ベストプラクティス

  • 検索動作に合わせてmin_gramとmax_gramを選択する

    • min_gram=2max_gram=3から始めてください。

    • min_gramは、ユーザーが入力すると予想される最も短いリテラルに設定してください。

    • max_gramは、意味のある部分文字列の典型的な長さに近づけてください。より大きなmax_gramはフィルタリングを改善しますが、スペースも増加します。

  • 低選択性のグラムを避ける

    高く反復するパターン(例:"aaaaaa")は弱いフィルタリングを提供し、限定的な利点しか得られない可能性があります。

  • 一貫した正規化

    使用ケースで必要であれば、インジェストされたテキストとクエリリテラルに同じ正規化(例:小文字化、トリミング)を適用してください。