Partitionsschlüssel verwenden
Dieser Leitfaden führt Sie durch die Verwendung des Partitionsschlüssels zur Beschleunigung des Datenabrufs in Ihrer Sammlung.
Übersicht
Sie können ein bestimmtes Feld in einer Sammlung als Partitionsschlüssel festlegen, so dass Milvus eingehende Entitäten in verschiedene Partitionen entsprechend ihrer jeweiligen Partitionswerte in diesem Feld verteilt. Dadurch können Entitäten mit demselben Schlüsselwert in einer Partition gruppiert werden, was die Suchleistung beschleunigt, da beim Filtern nach dem Schlüsselfeld keine irrelevanten Partitionen durchsucht werden müssen. Im Vergleich zu herkömmlichen Filtermethoden kann der Partitionsschlüssel die Abfrageleistung erheblich verbessern.
Sie können den Partitionsschlüssel verwenden, um eine Mehrmandantenfähigkeit zu implementieren. Für weitere Details zur Mehrmandantenfähigkeit lesen Sie bitte Mehrmandantenfähigkeit.
Aktivieren des Partitionsschlüssels
Um ein Feld als Partitionsschlüssel festzulegen, geben Sie beim Erstellen eines Auflistungsschemas partition_key_field
an.
Im folgenden Beispielcode bestimmt num_partitions
die Anzahl der zu erstellenden Partitionen. Standardmäßig ist er auf 64
eingestellt. Es wird empfohlen, den Standardwert beizubehalten.
Weitere Informationen zu Parametern finden Sie unter MilvusClient
, create_schema()
, und add_field()
in der SDK-Referenz.
Weitere Informationen zu Parametern finden Sie unter MilvusClientV2
, createSchema()
, und addField()
in der SDK-Referenz.
Weitere Informationen zu Parametern finden Sie unter MilvusClient
und createCollection()
in der SDK-Referenz.
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)
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());
const { MilvusClient, DataType, sleep } = require("@zilliz/milvus2-sdk-node")
const address = "http://localhost:19530"
async function main() {
// 1. Set up a Milvus Client
client = new MilvusClient({address});
// 2. Create a collection
// 2.1 Define fields
const fields = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
auto_id: false
},
{
name: "vector",
data_type: DataType.FloatVector,
dim: 5
},
{
name: "color",
data_type: DataType.VarChar,
max_length: 512,
is_partition_key: true
}
]
Nachdem Sie die Felder definiert haben, richten Sie die Indexparameter ein.
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}
}]
Schließlich können Sie eine Sammlung erstellen.
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
//
Partitionen auflisten
Sobald ein Feld einer Sammlung als Partitionsschlüssel verwendet wird, erstellt Milvus die angegebene Anzahl von Partitionen und verwaltet sie in Ihrem Namen. Daher können Sie die Partitionen in dieser Sammlung nicht mehr manipulieren.
Das folgende Snippet zeigt, dass 64 Partitionen in einer Sammlung erstellt werden können, sobald eines ihrer Felder als Partitionsschlüssel verwendet wird.
Daten einfügen
Sobald die Sammlung fertig ist, beginnen Sie mit dem Einfügen der Daten wie folgt:
Daten vorbereiten
# 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])
Sie können die Struktur der generierten Daten sehen, indem Sie den ersten Eintrag überprüfen.
{
id: 0,
vector: [
0.1275656405044483,
0.47417858592773277,
0.13858264437643286,
0.2390904907020377,
0.8447862593689635
],
color: 'blue',
tag: 2064,
color_tag: 'blue_2064'
}
Daten einfügen
Verwenden Sie die insert()
Methode, um die Daten in die Sammlung einzufügen.
Verwenden Sie die insert()
um die Daten in die Sammlung einzufügen.
Verwenden Sie die insert()
Methode, um die Daten in die Sammlung einzufügen.
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)"
# ]
# }
// 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
res = await client.insert({
collection_name: "test_collection",
data: data,
})
console.log(res.insert_cnt)
// Output
//
// 1000
//
Partitionsschlüssel verwenden
Sobald Sie die Sammlung indiziert und geladen sowie Daten eingefügt haben, können Sie eine Ähnlichkeitssuche mit dem Partitionsschlüssel durchführen.
Weitere Informationen zu den Parametern finden Sie unter search()
in der SDK-Referenz.
Weitere Informationen zu den Parametern finden Sie unter search()
in der SDK-Referenz.
Weitere Informationen zu Parametern finden Sie unter search()
in der SDK-Referenz.
Hinweise
Um eine Ähnlichkeitssuche unter Verwendung des Partitionsschlüssels durchzuführen, sollten Sie einen der folgenden Punkte in den booleschen Ausdruck der Suchanfrage aufnehmen:
expr='<partition_key>=="xxxx"'
expr='<partition_key> in ["xxx", "xxx"]'
Ersetzen Sie <partition_key>
durch den Namen des Feldes, das als Partitionsschlüssel bezeichnet wird.
# 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' }
// ]
//
Typische Anwendungsfälle
Sie können die Partitionsschlüssel-Funktion nutzen, um eine bessere Suchleistung zu erzielen und die Mandantenfähigkeit zu aktivieren. Dies kann durch Zuweisung eines mandantenspezifischen Wertes als Partitionsschlüsselfeld für jede Entität erfolgen. Bei der Suche oder Abfrage der Sammlung können Sie Entitäten nach dem mieterspezifischen Wert filtern, indem Sie das Partitionsschlüsselfeld in den booleschen Ausdruck aufnehmen. Dieser Ansatz gewährleistet die Datenisolierung nach Mandanten und vermeidet das Scannen unnötiger Partitionen.