使用 Partition Key
Partition Key 是基于 partition 的搜索优化解决方案。通过将特定标量 field 指定为 Partition Key,并在搜索期间基于 Partition Key 指定过滤条件,可以将搜索范围缩小到几个 partition,从而提高搜索效率。本文将介绍如何使用 Partition Key 以及相关注意事项。
概述
在 Milvus 中,您可以使用 partition 来实现数据隔离,并通过将搜索范围限制在特定 partition 内来提高搜索性能。如果您选择手动管理 partition,可以在一个 collection 中创建最多 1,024 个 partition,并根据特定规则将 entity 插入这些 partition,这样您就可以通过将搜索限制在特定数量的 partition 内来缩小搜索范围。
Milvus 引入了 Partition Key,让您可以在数据隔离中重用 partition,以克服在 collection 中可以创建的 partition 数量限制。创建 collection 时,您可以使用标量 field 作为 Partition Key。collection 准备就绪后,Milvus 在 collection 内创建指定数量的 partition。收到插入的 entity 时,Milvus 使用 entity 的 Partition Key 值计算哈希值,基于哈希值和 collection 的 partitions_num
属性执行模运算以获得目标 partition ID,并将 entity 存储在目标 partition 中。
下图说明了 Milvus 如何在启用或未启用 Partition Key 功能的 collection 中处理搜索请求。
-
如果禁用 Partition Key,Milvus 在 collection 内搜索与查询向量最相似的 entity。如果您知道哪个 partition 包含最相关的结果,可以缩小搜索范围。
-
如果启用 Partition Key,Milvus 根据搜索过滤器中指定的 Partition Key 值确定搜索范围,并仅扫描匹配的 partition 内的 entity。
使用 Partition Key
要使用 Partition Key,您需要
设置 Partition Key
要将标量 field 指定为 Partition Key,您需要在添加标量 field 时将其 is_partition_key
属性设置为 true
。
当您将标量 field 设置为 Partition Key 时,field 值不能为空或 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 中的标量 field 指定为 Partition Key 时,Milvus 会自动在 collection 中创建 16 个 partition。收到实体后,Milvus 根据此实体的 Partition Key 值选择一个 partition 并将实体存储在该 partition 中,导致某些或所有 partition 都保存具有不同 Partition Key 值的实体。
您还可以确定与 collection 一起创建的 partition 数量。这仅在您有一个标量 field 被指定为 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
}"
创建过滤条件
在启用了 Partition Key 功能的 collection 中进行 ANN 搜索时,您需要在搜索请求中包含涉及 Partition Key 的过滤表达式。在过滤表达式中,您可以将 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 的 field 名称。
使用 Partition Key 隔离
在多租户场景中,您可以将与租户身份相关的标量 field 指定为 partition key,并基于此标量 field 中的特定值创建过滤器。为了进一步提高类似场景中的搜索性能,Milvus 引入了 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" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
启用 Partition Key 隔离后,您仍然可以按照设置 Partition 数量中的描述设置 Partition Key 和 partition 数量。请注意,基于 Partition Key 的过滤器应仅包含特定的 Partition Key 值。