• 關於 Milvus
  • 開始使用
  • 概念
  • 使用者指南
  • 資料匯入
  • AI 工具
  • 管理指南
  • 工具
  • 整合
  • 教學
  • 常見問題
  • API Reference

NGRAM

Milvus 中的NGRAM 索引是為了加速對VARCHAR 欄位或JSON 欄位內特定 JSON 路徑的LIKE 查詢而建立的。在建立索引之前,Milvus 會將文字分割成固定長度n 的短小、重疊子串,稱為n-gram。例如,當n = 3 時,單字「Milvus」會被分割成 3 個字元:"Mil"、 "ilv"、" lvu 「」vus"。然後,這些 n-grams 會儲存在一個反向索引中,該索引會將每個 gram 對應到出現該 gram 的文件 ID。在查詢時,此索引允許 Milvus 快速將搜尋範圍縮小到一小組候選詞,從而大大加快了查詢的執行速度。

當您需要快速的前綴、後綴、下綴或通配符篩選時,請使用它,例如:

  • name LIKE "data%"

  • title LIKE "%vector%"

  • path LIKE "%json"

有關篩選表達語法的詳細資訊,請參閱基本運算符

如何運作

Milvus 在兩個階段的過程中實現NGRAM 索引:

  1. 建立索引:為每個文件產生 n-grams,並在擷取過程中建立反向索引。

  2. 加速查詢:使用索引過濾到一個小的候選集,然後驗證完全匹配。

階段 1:建立索引

在資料擷取過程中,Milvus 會執行兩個主要步驟來建立 NGRAM 索引:

  1. 將文字分解成 n-grams:Milvus 在目標欄位中的每個字串上滑動一個n的視窗,並擷取重疊的子串或n-gram。這些子串的長度在可設定的範圍內,[min_gram, max_gram].

    • min_gram:要產生的最短 n-gram。這也定義了可從索引獲益的最小查詢子串長度。

    • max_gram:要產生的最長 n-gram。在查詢時,它也會用來作為分割長查詢字串時的最大視窗大小。

    例如,以min_gram=2max_gram=3 為例,字串"AI database" 拆分如下:

Build Ngram Index 建立 Ngram 索引

- **2-grams:** `AI`, `I_`, `_d`, `da`, `at`, ...

- **3-grams:** `AI_`, `I_d`, `_da`, `dat`, `ata`, ...

<div class="alert note">

- For a range `[min_gram, max_gram]`, Milvus generates all n-grams for every length between the two values (inclusive). For example, with `[2,4]` and the word `"text"`, Milvus generates:

- **2-grams:** `te`, `ex`, `xt`

- **3-grams:** `tex`, `ext`

- **4-grams:** `text`

- N-gram decomposition is character-based and language-agnostic. For example, in Chinese, `"向量数据库"` with `min_gram = 2` is decomposed into: `"向量"`, `"量数"`, `"数据"`, `"据库"`.

- Spaces and punctuation are treated as characters during decomposition.

- Decomposition preserves original case, and matching is case-sensitive. For example, `"Database"` and `"database"` will generate different n-grams and require exact case matching during queries.

</div>
  1. 建立倒置索引:建立倒置索引,將每個產生的 n-gram 對應到包含該 n-gram 的文件 ID 清單。

    例如,如果 2-gram"AI" 出現在 ID 為 1、5、6、8 和 9 的文件中,索引就會記錄{"AI": [1, 5, 6, 8, 9]} 。此索引可在查詢時使用,以快速縮小搜尋範圍。

Build Ngram Index 2 建立 Ngram 索引 2

<div class="alert note">

A wider `[min_gram, max_gram]` range creates more grams and larger mapping lists. If memory is tight, consider mmap mode for very large posting lists. For details, refer to [Use mmap](https://zilliverse.feishu.cn/wiki/P3wrwSMNNihy8Vkf9p6cTsWYnTb).

</div>

第二階段:加速查詢

LIKE 過濾器被執行時,Milvus 會使用 NGRAM 索引來加速查詢,步驟如下:

Accelerate Queries 加速查詢

  1. 擷取查詢詞:LIKE 表達式中萃取不含通配符的連續子串 (例如"%database%" 變成"database")。

  2. 分解查詢詞:根據查詢詞的長度 (L) 以及min_grammax_gram 的設定,將查詢詞分解為n 個字元

    • 如果L < min_gram ,則無法使用索引,查詢會退回到完整掃描。

    • 如果是min_gram ≤ L ≤ max_gram ,則整個查詢詞會被視為單一 n-gram,不需要進一步分解。

    • 如果是L > max_gram ,查詢詞會使用等於max_gram 的視窗大小分解成重疊的格。

    舉例來說,如果max_gram 設定為3 ,而查詢詞為"database" ,長度為8,則會分解為"dat","ata","tab" 等 3 個克的子串。

  3. 尋找每個格及交集:Milvus 在倒排索引中尋找每個查詢格,然後交集所得的文件 ID 清單,找出一小組候選文件。這些候選文件包含查詢中的所有語法。

  4. 驗證並返回結果:然後,原始的LIKE 過濾器只會應用在小的候選集上做最後檢查,以找出完全符合的結果。

建立 NGRAM 索引

您可以在VARCHAR 欄位或JSON 欄位內的特定路徑上建立 NGRAM 索引。

範例 1:在 VARCHAR 欄位上建立

對於VARCHAR 欄位,您只需指定field_name 並配置min_grammax_gram

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530") # Replace with your server address

# Assume you have defined a VARCHAR field named "text" in your collection schema

# Prepare index parameters
index_params = client.prepare_index_params()

# Add NGRAM index on the "text" field
index_params.add_index(
    field_name="text",   # Target VARCHAR field
    index_type="NGRAM",           # Index type is NGRAM
    index_name="ngram_index",     # Custom name for the index
    min_gram=2,                   # Minimum substring length (e.g., 2-gram: "st")
    max_gram=3                    # Maximum substring length (e.g., 3-gram: "sta")
)

# Create the index on the collection
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 索引是對字串操作的。

# Assume you have defined a JSON field named "json_field" in your collection schema, with a JSON path named "body"

# Prepare index parameters
index_params = client.prepare_index_params()

# Add NGRAM index on a JSON field
index_params.add_index(
    field_name="json_field",              # Target JSON field
    index_type="NGRAM",                   # Index type is NGRAM
    index_name="json_ngram_index",        # Custom index name
    min_gram=2,                           # Minimum n-gram length
    max_gram=4,                           # Maximum n-gram length
    params={
        "json_path": "json_field[\"body\"]",  # Path to the value inside the JSON field
        "json_cast_type": "varchar"                  # Required: cast the value to varchar
    }
)

# Create the index on the collection
client.create_index(
    collection_name="Documents",
    index_params=index_params
)

在本範例中

  • 只索引json_field["body"] 的值。

  • 在 n-gram 標記化之前,該值會被轉換為VARCHAR

  • Milvus 會產生長度為 2 到 4 的子串,並將它們儲存在反向索引中。

有關如何索引 JSON 欄位的詳細資訊,請參閱JSON 索引

由 NGRAM 加速的查詢

若要套用 NGRAM 索引:

  • 查詢的目標必須是有NGRAM 索引的VARCHAR 欄位(或 JSON 路徑)。

  • LIKE 模式的字面部分必須至少有min_gram 個字元長(例如,如果您最短的預期查詢字詞是 2 個字元,請在建立索引時設定 min_gram=2)。

支援的查詢類型:

  • 前綴匹配

    # Match any string that starts with the substring "database"
    filter = 'text LIKE "database%"'
    
  • 後綴匹配

    # Match any string that ends with the substring "database"
    filter = 'text LIKE "%database"'
    
  • 後綴匹配

    # Match any string that contains the substring "database" anywhere
    filter = 'text LIKE "%database%"'
    
  • 通配符匹配

    Milvus 支援% (零個或多個字元) 和_ (正好一個字元)。

    # Match any string where "st" appears first, and "um" appears later in the text 
    filter = 'text LIKE "%st%um%"'
    
  • JSON 路徑查詢

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

有關篩選表達式語法的更多資訊,請參閱基本運算符號。

刪除索引

使用drop_index() 方法從集合中移除現有的索引。

client.drop_index(
    collection_name="Documents",   # Name of the collection
    index_name="ngram_index" # Name of the index to drop
)

使用注意事項

  • 欄位類型:支援VARCHARJSON 欄位。對於 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=2,max_gram=3 開始。

    • min_gram 設定為您預期使用者會輸入的最短文字。

    • max_gram 設定在有意義子串的典型長度附近;較大的max_gram 可以改善過濾,但會增加空間。

  • 避免低選擇性克

    高度重複的模式 (例如:"aaaaaa"),過濾效果較弱,可能產生有限的效益。

  • 一致地標準化

    如果您的使用情況需要,請將相同的規範化方式套用於擷取的文字與查詢字面意義(例如:降低大小寫、修剪)。