使用分區鑰匙
分區關鍵是基於分區的搜尋最佳化解決方案。透過指定特定的標量欄位為分區關鍵 (Partition Key),並在搜尋過程中根據分區關鍵指定篩選條件,可將搜尋範圍縮小為數個分區,進而提高搜尋效率。本文將介紹如何使用分區關鍵及相關注意事項。
概述
在 Milvus 中,您可以使用磁碟分割來實現資料分隔,並透過限制搜尋範圍到特定磁碟分割來改善搜尋效能。如果您選擇手動管理分區,您可以在一個集合中建立最多 1,024 個分區,並根據特定規則插入實體到這些分區中,這樣您就可以通過限制在特定數量的分區中進行搜索來縮窄搜索範圍。
Milvus 引入了分區鑰匙,讓您在資料分隔中重複使用分區,以克服在集合中建立分區數量的限制。當建立一個資料集時,您可以使用一個標量欄位作為分割鍵。一旦集合就緒,Milvus 會在集合內建立指定數量的分區。當接收到插入的實體時,Milvus 會使用實體的 Partition Key 值計算雜湊值,根據雜湊值和集合的partitions_num 屬性執行 modulo 運算,以獲得目標分割 ID,並將實體儲存到目標分割中。
分割區與分割區金鑰
下圖說明 Milvus 在啟用或未啟用分割區金鑰功能的情況下,如何處理集合中的搜尋要求。
如果禁用了分區鍵功 能,Milvus 會在資料集中搜尋與查詢向量最相似的實體。如果您知道哪個分區包含最相關的結果,就可以縮小搜尋範圍。
如果啟用了分割區金鑰,Milvus 會根據搜尋篩選器中指定的分割區金鑰值來決定搜尋範圍,並且只掃描分割區中符合條件的實體。
使用和不使用磁碟分割索引鍵
使用分割區金鑰
要使用分區鍵值,您需要
設定要建立的分割區數量(選用),以及
設定分割區金鑰
若要指定標量欄位為分割區金鑰,您需要在新增標量欄位時,將其is_partition_key 屬性設定為true 。
當您設定標量欄位為分割區金鑰時,欄位值不能為空或 null。
from pymilvus import (
MilvusClient, DataType
)
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
schema = client.create_schema()
schema.add_field(field_name="id",
datatype=DataType.INT64,
is_primary=True)
schema.add_field(field_name="vector",
datatype=DataType.FLOAT_VECTOR,
dim=5)
# Add the partition key
schema.add_field(
field_name="my_varchar",
datatype=DataType.VARCHAR,
max_length=512,
is_partition_key=True,
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
// Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
// Add the partition key
schema.addField(AddFieldReq.builder()
.fieldName("my_varchar")
.dataType(DataType.VarChar)
.maxLength(512)
.isPartitionKey(true)
.build());
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v2/column"
"github.com/milvus-io/milvus/client/v2/entity"
"github.com/milvus-io/milvus/client/v2/index"
"github.com/milvus-io/milvus/client/v2/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "localhost:19530"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: milvusAddr,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
schema := entity.NewSchema().WithDynamicFieldEnabled(false)
schema.WithField(entity.NewField().
WithName("id").
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true),
).WithField(entity.NewField().
WithName("my_varchar").
WithDataType(entity.FieldTypeVarChar).
WithIsPartitionKey(true).
WithMaxLength(512),
).WithField(entity.NewField().
WithName("vector").
WithDataType(entity.FieldTypeFloatVector).
WithDim(5),
)
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
// 3. Create a collection in customized setup mode
// 3.1 Define fields
const fields = [
{
name: "my_varchar",
data_type: DataType.VarChar,
max_length: 512,
is_partition_key: true
}
]
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
},
{
"fieldName": "my_varchar",
"dataType": "VarChar",
"isPartitionKey": true,
"elementTypeParams": {
"max_length": 512
}
}
]
}'
設定分割區號碼
當您指定一個集合中的標量欄位為分區鍵時,Milvus 會自動在集合中建立 16 個分區。當接收到一個實體時,Milvus 會根據該實體的 Partition Key 值選擇一個分區,並將該實體存儲在該分區中,結果是某些或所有分區持有不同 Partition Key 值的實體。
您也可以決定要與集合一起建立的分割區數量。只有當您指定一個標量欄位作為 Partition Key 時,這才有效。
client.create_collection(
collection_name="my_collection",
schema=schema,
num_partitions=128
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.numPartitions(128)
.build();
client.createCollection(createCollectionReq);
err = client.CreateCollection(ctx,
milvusclient.NewCreateCollectionOption("my_collection", schema).
WithNumPartitions(128))
if err != nil {
fmt.Println(err.Error())
// handle error
}
await client.create_collection({
collection_name: "my_collection",
schema: schema,
num_partitions: 128
})
export params='{
"partitionsNum": 128
}'
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
建立篩選條件
在啟用了分割區金鑰功能的資料集中執行 ANN 搜尋時,您需要在搜尋請求中包含涉及分割區金鑰的篩選表達式。在篩選表達式中,您可以限制 Partition Key 的值在特定範圍內,這樣 Milvus 就可以將搜尋範圍限制在相應的分區內。
執行刪除作業時,建議包含指定單一磁碟分割索引鍵的篩選表達式,以達到更有效率的刪除。此方法可將刪除作業限制在特定的分割區內,減少壓縮期間的寫入擴大,並節省壓縮和索引的資源。
以下範例示範基於特定的分割區金鑰值和一組分割區金鑰值,進行基於分割區金鑰的篩選。
# Filter based on a single partition key value, or
filter='partition_key == "x" && <other conditions>'
# Filter based on multiple partition key values
filter='partition_key in ["x", "y", "z"] && <other conditions>'
// Filter based on a single partition key value, or
String filter = "partition_key == 'x' && <other conditions>";
// Filter based on multiple partition key values
String filter = "partition_key in ['x', 'y', 'z'] && <other conditions>";
// Filter based on a single partition key value, or
filter = "partition_key == 'x' && <other conditions>"
// Filter based on multiple partition key values
filter = "partition_key in ['x', 'y', 'z'] && <other conditions>"
// Filter based on a single partition key value, or
const filter = 'partition_key == "x" && <other conditions>'
// Filter based on multiple partition key values
const filter = 'partition_key in ["x", "y", "z"] && <other conditions>'
# Filter based on a single partition key value, or
export filter='partition_key == "x" && <other conditions>'
# Filter based on multiple partition key values
export filter='partition_key in ["x", "y", "z"] && <other conditions>'
您必須以指定為分割區金鑰的欄位名稱取代partition_key 。
使用分割區金鑰隔離
在多租戶情境中,您可以指定與租戶身分相關的標量欄位為分割區金鑰,並根據此標量欄位中的特定值建立篩選器。為了進一步改善類似情況下的搜尋效能,Milvus 介紹了分割區金鑰隔離功能。
分割區金鑰隔離
如上圖所示,Milvus 根據分區鍵值將實體分組,並為每個分組建立獨立索引。當接收到搜尋要求時,Milvus 會根據過濾條件中指定的 Partition Key 值找到索引,並將搜尋範圍限制在索引所包含的實體內,從而避免在搜尋過程中掃描不相關的實體,大大提升搜尋效能。
一旦啟用「分割區金鑰區隔」,您必須在基於分割區金鑰的篩選條件中只包含一個特定值,以便 Milvus 能夠在符合條件的索引所包含的實體中限制搜尋範圍。
目前,「分割區金鑰隔離」功能僅適用於索引類型設定為 HNSW 的搜尋。
啟用分割區金鑰隔離
以下程式碼範例說明如何啟用分割區金鑰隔離。
client.create_collection(
collection_name="my_collection",
schema=schema,
properties={"partitionkey.isolation": True}
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;
Map<String, String> properties = new HashMap<>();
properties.put("partitionkey.isolation", "true");
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.properties(properties)
.build();
client.createCollection(createCollectionReq);
err = client.CreateCollection(ctx,
milvusclient.NewCreateCollectionOption("my_collection", schema).
WithProperty("partitionkey.isolation", true))
if err != nil {
fmt.Println(err.Error())
// handle error
}
res = await client.alterCollection({
collection_name: "my_collection",
properties: {
"partitionkey.isolation": true
}
})
export params='{
"partitionKeyIsolation": true
}'
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
啟用磁碟分割區金鑰隔離後,您仍可依照Set Partition Numbers(設定磁碟分割區號碼)一節所述,設定磁碟分割區金鑰和磁碟分割區號碼。請注意,基於分割區金鑰的篩選程式應該只包含特定的分割區金鑰值。