使用 Partition Key
Partition 关键字是一种基于 Partition 的搜索优化解决方案。通过指定特定标量字段作为 Partition Key,并在搜索过程中根据 Partition Key 指定过滤条件,可以将搜索范围缩小到多个 Partition,从而提高搜索效率。本文将介绍如何使用 Partition Key 以及相关注意事项。
概述
在 Milvus 中,你可以使用 Partition 来实现数据隔离,并通过将搜索范围限制在特定 Partition 来提高搜索性能。如果选择手动管理 Partition,可以在 Collection 中创建最多 1,024 个 Partition,并根据特定规则将实体插入这些 Partition,这样就可以通过限制在特定数量的 Partition 内进行搜索来缩小搜索范围。
Milvus 引入了 Partition Key,供你在数据隔离中重复使用 Partition,以克服在 Collection 中创建 Partition 数量的限制。创建 Collection 时,可以使用标量字段作为 Partition Key。一旦 Collection 准备就绪,Milvus 就会在 Collection 内创建指定数量的 Partition。接收到插入的实体后,Milvus 会使用实体的 Partition Key 值计算哈希值,根据哈希值和 Collection 的partitions_num 属性执行求模操作,以获得目标 Partition ID,并将实体存储到目标 Partition 中。
Partition 与 Partition Key
下图说明了在启用或未启用 Partition Key 功能的情况下,Milvus 如何处理 Collection 中的搜索请求。
-
如果禁用了 Partition Key,Milvus 会在 Collection 中搜索与查询向量最相似的实体。如果知道哪个 Partition 包含最相关的结果,就可以缩小搜索范围。
-
如果启用了 Partition 关键字,Milvus 会根据搜索过滤器中指定的 Partition 关键字值确定搜索范围,并只扫描 Partition 内匹配的实体。
有无 Partition Key
使用 Partition Key
要使用 Partition Key,您需要
设置 Partition Key
要将标量字段指定为 Partition Key,需要在添加标量字段时将其is_partition_key 属性设置为true 。
说明 将标量字段设置为 Partition Key 时,字段值不能为空或 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
}
}
]
}'
设置 Partition 编号
当你指定一个 Collection 中的标量字段作为 Partition Key 时,Milvus 会自动在 Collection 中创建 16 个 Partition。接收到实体后,Milvus 会根据该实体的 Partition Key 值选择一个 Partition,并将实体存储到 Partition 中,从而导致部分或全部 Partition 持有不同 Partition Key 值的实体。
您还可以确定与 Collection 一起创建的 Partition 数量。只有将标量字段指定为 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" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
创建过滤条件
在启用 Partition 关键字功能的 Collection 中进行 ANN 搜索时,需要在搜索请求中包含涉及 Partition 关键字的过滤表达式。在过滤表达式中,你可以将 Partition Key 的值限制在特定范围内,这样 Milvus 就会将搜索范围限制在相应的 Partition 内。
在执行删除操作时,建议加入指定单一 Partition Key 的过滤表达式,以实现更高效的删除。这种方法将删除操作限制在特定 Partition 内,减少了压缩过程中的写入放大,节省了用于压缩和索引的资源。
下面的示例演示了基于 Partition Key 的过滤,它基于一个特定的 Partition Key 值和一组 Partition Key 值。
# 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替换为指定为 Partition Key 的字段名称。
使用 Partition Key 隔离
在多租户场景中,可以将与租户身份相关的标量字段指定为 Partition Key,并根据此标量字段中的特定值创建过滤器。为了进一步提高类似情况下的搜索性能,Milvus 引入了 Partition Key 隔离功能。
Partition Key 隔离
如上图所示,Milvus 根据 Partition Key 值对实体进行分组,并为每个分组创建单独的索引。收到搜索请求后,Milvus 会根据过滤条件中指定的 Partition Key 值定位索引,并将搜索范围限制在索引所包含的实体内,从而避免在搜索过程中扫描不相关的实体,大大提高搜索性能。
启用 "Partition Key 隔离 "后,必须在基于 Partition Key 的过滤条件中只包含一个特定值,这样 Milvus 才能在匹配的索引所包含的实体内限制搜索范围。
说明 目前,Partition Key 隔离功能只适用于索引类型设置为 HNSW 的搜索。
启用 Partition Key 隔离功能
以下代码示例演示了如何启用 Partition Key 隔离。
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" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
启用 Partition Key 隔离后,仍可按照设置 Partition 编号中的说明设置 Partition Key 和 Partition编号。请注意,基于 Partition Key 的过滤器应只包含特定的 Partition Key 值。