使用 Partition Key
本指南将指导您使用 Partition Key 来加速从 Collection 中检索数据。
概述
你可以将 Collection 中的一个特定字段设置为 Partition Key,这样 Milvus 就会根据这个字段中各自的 Partition 值,将进入的实体分配到不同的 Partition 中。这样,具有相同键值的实体就会被归类到一个 Partition 中,从而在通过键字段进行过滤时,无需扫描无关的 Partition,从而加快了搜索性能。与传统的过滤方法相比,Partition Key 可以大大提高查询性能。
可以使用 Partition Key 实现多租户。有关多租户的详细信息,请阅读 多租户。
启用 Partition Key
要将某个字段设置为 Partition Key,请在创建 Collection Schema 时指定 partition_key_field。
在下面的示例代码中,num_partitions 决定将创建的 Partition 数量。默认情况下,它被设置为 64。建议保留默认值。
- Python
- Java
- Node.js
- Go
- cURL
有关参数的详细说明,请参阅 SDK 参考中的 MilvusClient、create_schema() 和 add_field()。
import random, time
from pymilvus import connections, MilvusClient, DataType
SERVER_ADDR = "http://localhost:19530"
# 1. Set up a Milvus client
client = MilvusClient(
uri=SERVER_ADDR
)
# 2. Create a collection
schema = MilvusClient.create_schema(
auto_id=False,
enable_dynamic_field=True,
partition_key_field="color",
num_partitions=64 # Number of partitions. Defaults to 64.
)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="color", datatype=DataType.VARCHAR, max_length=512)
有关参数的详细说明,请参阅 SDK 参考中的 MilvusClientV2、createSchema() 和 addField()。
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
String CLUSTER_ENDPOINT = "http://localhost:19530";
// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
.uri(CLUSTER_ENDPOINT)
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
// 2. Create a collection in customized setup mode
// 2.1 Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);
// 2.2 Add fields to schema
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(false)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("color")
.dataType(DataType.VarChar)
.maxLength(512)
.isPartitionKey(true)
.build());
有关参数的详细说明,请参阅 SDK 参考中的 MilvusClient 和 createCollection()。
const {DataType, MilvusClient} = require("@zilliz/milvus2-sdk-node");
const client = new MilvusClient({address: "http://localhost:19530"});
const fields = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
autoID: false,
},
{
name: "vector",
data_type: DataType.FloatVector,
dim: 5,
},
{
name: "color",
data_type: DataType.VarChar,
max_length: 512,
is_partition_key: true,
},
];
定义字段后,设置索引参数。
- Python
- Java
- Node.js
- Go
- cURL
index_params = MilvusClient.prepare_index_params()
index_params.add_index(
field_name="id",
index_type="STL_SORT"
)
index_params.add_index(
field_name="color",
index_type="Trie"
)
index_params.add_index(
field_name="vector",
index_type="IVF_FLAT",
metric_type="L2",
params={"nlist": 1024}
)
// 2.3 Prepare index parameters
Map<String, Object> params = new HashMap<>();
params.put("nlist", 1024);
IndexParam indexParamForVectorField = IndexParam.builder()
.fieldName("vector")
.indexType(IndexParam.IndexType.IVF_FLAT)
.metricType(IndexParam.MetricType.IP)
.extraParams(params)
.build();
List<IndexParam> indexParams = new ArrayList<>();
indexParams.add(indexParamForVectorField);
// 2.2 Prepare index parameters
const index_params = [{
field_name: "color",
index_type: "Trie"
},{
field_name: "id",
index_type: "STL_SORT"
},{
field_name: "vector",
index_type: "IVF_FLAT",
metric_type: "IP",
params: { nlist: 1024}
}]
最后,您可以创建一个 Collection。
- Python
- Java
- Node.js
- Go
- cURL
client.create_collection(
collection_name="test_collection",
schema=schema,
index_params=index_params
)
// 2.4 Create a collection with schema and index parameters
CreateCollectionReq customizedSetupReq = CreateCollectionReq.builder()
.collectionName("test_collection")
.collectionSchema(schema)
.indexParams(indexParams)
.build();
client.createCollection(customizedSetupReq);
// 2.3 Create a collection with fields and index parameters
res = await client.createCollection({
collection_name: "test_collection",
fields: fields,
index_params: index_params,
})
console.log(res.error_code)
// Output
//
// Success
//
列出 Partition
一旦 Collection 的某个字段被用作 Partition Key,Milvus 就会创建指定数量的 Partition,并代表你管理它们。因此,你不能再操作此 Collection 中的 Partition。
下面的代码段演示了一旦某个 Collection 的某个字段被用作 Partition Key,该 Collection 中就会出现 64 个 Partition。
插入数据
Collection 准备就绪后,按如下步骤开始插入数据:
准备数据
- Python
- Java
- Node.js
- Go
- cURL
# 3. Insert randomly generated vectors
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []
for i in range(1000):
current_color = random.choice(colors)
current_tag = random.randint(1000, 9999)
data.append({
"id": i,
"vector": [ random.uniform(-1, 1) for _ in range(5) ],
"color": current_color,
"tag": current_tag,
"color_tag": f"{current_color}_{str(current_tag)}"
})
print(data[0])
// 3. Insert randomly generated vectors
List<String> colors = Arrays.asList("green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey");
List<JsonObject> data = new ArrayList<>();
Gson gson = new Gson();
Random rand = new Random();
for (int i=0; i<1000; i++) {
String current_color = colors.get(rand.nextInt(colors.size()-1));
int current_tag = rand.nextInt(8999) + 1000;
JsonObject row = new JsonObject();
row.addProperty("id", (long) i);
row.add("vector", gson.toJsonTree(Arrays.asList(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat())));
row.addProperty("color", current_color);
row.addProperty("tag", current_tag);
row.addProperty("color_tag", current_color + "_" + (rand.nextInt(8999) + 1000));
data.add(row);
}
System.out.println(data.get(0));
// 3. Insert randomly generated vectors
const colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
var data = []
for (let i = 0; i < 1000; i++) {
const current_color = colors[Math.floor(Math.random() * colors.length)]
const current_tag = Math.floor(Math.random() * 8999 + 1000)
data.push({
id: i,
vector: [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()],
color: current_color,
tag: current_tag,
color_tag: `${current_color}_${current_tag}`
})
}
console.log(data[0])
您可以通过查看第一个条目来查看生成数据的结构。
{
id: 0,
vector: [
0.1275656405044483,
0.47417858592773277,
0.13858264437643286,
0.2390904907020377,
0.8447862593689635
],
color: 'blue',
tag: 2064,
color_tag: 'blue_2064'
}
插入数据
- Python
- Java
- Node.js
- Go
- cURL
使用 insert() 方法将数据插入 Collection。
res = client.insert(
collection_name="test_collection",
data=data
)
print(res)
# Output
#
# {
# "insert_count": 1000,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(990 more items hidden)"
# ]
# }
使用 insert() 方法将数据插入 Collection。
// 3.1 Insert data into the collection
InsertReq insertReq = InsertReq.builder()
.collectionName("test_collection")
.data(data)
.build();
InsertResp insertResp = client.insert(insertReq);
System.out.println(insertResp.getInsertCnt());
// Output:
// 1000
使用 insert() 方法将数据插入 Collection。
res = await client.insert({
collection_name: "test_collection",
data: data,
})
console.log(res.insert_cnt)
// Output
//
// 1000
//
使用 Partition Key
索引和加载 Collection 以及插入数据后,就可以使用 Partition Key 进行相似性搜索。
有关参数的更多信息,请参阅 search() 中的
备注
要使用 Partition Key 进行相似性搜索,应在搜索请求的布尔表达式中包含以下任一项:
-
expr='<partition_key>=="xxxx"' -
expr='<partition_key> in ["xxx", "xxx"]'
请将 <partition_key> 替换为指定为 Partition Key 的字段名称。
- Python
- Java
- Node.js
- Go
- cURL
# 4. Search with partition key
query_vectors = [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]
res = client.search(
collection_name="test_collection",
data=query_vectors,
filter="color == 'green'",
search_params={"metric_type": "L2", "params": {"nprobe": 10}},
output_fields=["id", "color_tag"],
limit=3
)
print(res)
# Output
#
# [
# [
# {
# "id": 970,
# "distance": 0.5770174264907837,
# "entity": {
# "id": 970,
# "color_tag": "green_9828"
# }
# },
# {
# "id": 115,
# "distance": 0.6898155808448792,
# "entity": {
# "id": 115,
# "color_tag": "green_4073"
# }
# },
# {
# "id": 899,
# "distance": 0.7028976678848267,
# "entity": {
# "id": 899,
# "color_tag": "green_9897"
# }
# }
# ]
# ]
// 4. Search with partition key
List<BaseVector> query_vectors = Collections.singletonList(new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f}));
SearchReq searchReq = SearchReq.builder()
.collectionName("test_collection")
.data(query_vectors)
.filter("color == \"green\"")
.topK(3)
.outputFields(Collections.singletonList("color_tag"))
.build();
SearchResp searchResp = client.search(searchReq);
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
// Output:
// SearchResp.SearchResult(entity={color_tag=green_4945}, score=1.192079, id=542)
// SearchResp.SearchResult(entity={color_tag=green_4633}, score=0.9138917, id=144)
// SearchResp.SearchResult(entity={color_tag=green_8038}, score=0.8381896, id=962)
// 4. Search with partition key
const query_vectors = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = await client.search({
collection_name: "test_collection",
data: query_vectors,
filter: "color == 'green'",
output_fields: ["color_tag"],
limit: 3
})
console.log(res.results)
// Output
//
// [
// { score: 2.402090549468994, id: '135', color_tag: 'green_2694' },
// { score: 2.3938629627227783, id: '326', color_tag: 'green_7104' },
// { score: 2.3235254287719727, id: '801', color_tag: 'green_3162' }
// ]
//
典型用例
您可以利用 Partition Key 功能实现更好的搜索性能并启用多租户功能。具体做法是为每个实体指定一个特定于租户的值作为 Partition Key 字段。在搜索或查询 Collection 时,可以通过在布尔表达式中包含 Partition Key 字段,根据租户特定值过滤实体。这种方法可确保按租户进行数据隔离,并避免扫描不必要的 Partition。