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 索引:
建立索引:為每個文件產生 n-grams,並在擷取過程中建立反向索引。
加速查詢:使用索引過濾到一個小的候選集,然後驗證完全匹配。
階段 1:建立索引
在資料擷取過程中,Milvus 會執行兩個主要步驟來建立 NGRAM 索引:
將文字分解成 n-grams:Milvus 在目標欄位中的每個字串上滑動一個n的視窗,並擷取重疊的子串或n-gram。這些子串的長度在可設定的範圍內,
[min_gram, max_gram].min_gram:要產生的最短 n-gram。這也定義了可從索引獲益的最小查詢子串長度。max_gram:要產生的最長 n-gram。在查詢時,它也會用來作為分割長查詢字串時的最大視窗大小。
例如,以
min_gram=2和max_gram=3為例,字串"AI database"拆分如下:
建立 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>
建立倒置索引:建立倒置索引,將每個產生的 n-gram 對應到包含該 n-gram 的文件 ID 清單。
例如,如果 2-gram
"AI"出現在 ID 為 1、5、6、8 和 9 的文件中,索引就會記錄{"AI": [1, 5, 6, 8, 9]}。此索引可在查詢時使用,以快速縮小搜尋範圍。
建立 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 索引來加速查詢,步驟如下:
加速查詢
擷取查詢詞:從
LIKE表達式中萃取不含通配符的連續子串 (例如"%database%"變成"database")。分解查詢詞:根據查詢詞的長度 (
L) 以及min_gram和max_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 個克的子串。尋找每個格及交集:Milvus 在倒排索引中尋找每個查詢格,然後交集所得的文件 ID 清單,找出一小組候選文件。這些候選文件包含查詢中的所有語法。
驗證並返回結果:然後,原始的
LIKE過濾器只會應用在小的候選集上做最後檢查,以找出完全符合的結果。
建立 NGRAM 索引
您可以在VARCHAR 欄位或JSON 欄位內的特定路徑上建立 NGRAM 索引。
範例 1:在 VARCHAR 欄位上建立
對於VARCHAR 欄位,您只需指定field_name 並配置min_gram 和max_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
)
使用注意事項
欄位類型:支援
VARCHAR和JSON欄位。對於 JSON,同時提供params.json_path和params.json_cast_type="varchar"。Unicode:NGRAM 分解以字元為基礎,與語言無關,並包含空白和標點符號。
時空權衡:更寬的克數範圍
[min_gram, max_gram]會產生更多的克數和更大的索引。如果記憶體緊張,可考慮mmap模式來處理大型張貼清單。如需詳細資訊,請參閱使用 mmap。不變性:
min_gram和max_gram無法就地變更,必須重新建立索引才能調整。
最佳做法
選擇 min_gram 和 max_gram 以符合搜尋行為
從
min_gram=2,max_gram=3開始。將
min_gram設定為您預期使用者會輸入的最短文字。將
max_gram設定在有意義子串的典型長度附近;較大的max_gram可以改善過濾,但會增加空間。
避免低選擇性克
高度重複的模式 (例如:
"aaaaaa"),過濾效果較弱,可能產生有限的效益。一致地標準化
如果您的使用情況需要,請將相同的規範化方式套用於擷取的文字與查詢字面意義(例如:降低大小寫、修剪)。