Partitionsschlüssel verwenden

Der Partitionsschlüssel ist eine Lösung zur Suchoptimierung auf der Grundlage von Partitionen. Indem man ein bestimmtes skalares Feld als Partitionsschlüssel bestimmt und während der Suche Filterbedingungen auf der Grundlage des Partitionsschlüssels festlegt, kann der Suchbereich auf mehrere Partitionen eingegrenzt werden, wodurch die Sucheffizienz verbessert wird. In diesem Artikel werden die Verwendung des Partitionsschlüssels und damit verbundene Überlegungen vorgestellt.

Überblick

In Milvus können Sie Partitionen verwenden, um eine Datentrennung zu implementieren und die Suchleistung zu verbessern, indem Sie den Suchbereich auf bestimmte Partitionen beschränken. Wenn Sie sich für die manuelle Verwaltung von Partitionen entscheiden, können Sie maximal 1.024 Partitionen in einer Sammlung erstellen und Entitäten auf der Grundlage einer bestimmten Regel in diese Partitionen einfügen, so dass Sie den Suchbereich einschränken können, indem Sie die Suche auf eine bestimmte Anzahl von Partitionen beschränken.

Milvus führt den Partitionsschlüssel ein, mit dem Sie Partitionen in der Datentrennung wiederverwenden können, um die Begrenzung der Anzahl der Partitionen zu überwinden, die Sie in einer Sammlung erstellen können. Bei der Erstellung einer Sammlung können Sie ein skalares Feld als Partitionsschlüssel verwenden. Sobald die Sammlung fertig ist, erstellt Milvus die angegebene Anzahl von Partitionen innerhalb der Sammlung. Beim Empfang einer eingefügten Entität berechnet Milvus einen Hash-Wert unter Verwendung des Partitionsschlüsselwerts der Entität, führt eine Modulo-Operation basierend auf dem Hash-Wert und der partitions_num Eigenschaft der Sammlung aus, um die Zielpartitions-ID zu erhalten, und speichert die Entität in der Zielpartition.

Partition Vs Partition Key Partition vs. Partitionsschlüssel

Die folgende Abbildung zeigt, wie Milvus die Suchanfragen in einer Sammlung mit und ohne aktivierter Partitionsschlüssel-Funktion verarbeitet.

  • Wenn der Partitionsschlüssel deaktiviert ist, sucht Milvus nach Entitäten, die dem Abfragevektor innerhalb der Sammlung am ähnlichsten sind. Sie können den Suchbereich eingrenzen, wenn Sie wissen, welche Partition die relevantesten Ergebnisse enthält.

  • Wenn der Partitionsschlüssel aktiviert ist, bestimmt Milvus den Suchbereich basierend auf dem in einem Suchfilter angegebenen Partitionsschlüsselwert und durchsucht nur die Entitäten innerhalb der Partitionen, die übereinstimmen.

With And Without Partition Key Mit und ohne Partitionsschlüssel

Partitionsschlüssel verwenden

Um den Partitionsschlüssel zu verwenden, müssen Sie

Partitionsschlüssel festlegen

Um ein Skalarfeld als Partitionsschlüssel festzulegen, müssen Sie das Attribut is_partition_key auf true setzen, wenn Sie das Skalarfeld hinzufügen.

Wenn Sie ein Skalarfeld als Partitionsschlüssel festlegen, können die Feldwerte nicht leer oder null sein.

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
                }
            }
        ]
    }'

Partitionsnummern festlegen

Wenn Sie ein skalares Feld in einer Sammlung als Partitionsschlüssel festlegen, erstellt Milvus automatisch 16 Partitionen in der Sammlung. Beim Empfang einer Entität wählt Milvus eine Partition basierend auf dem Partitionsschlüsselwert dieser Entität und speichert die Entität in der Partition, was dazu führt, dass einige oder alle Partitionen Entitäten mit unterschiedlichen Partitionsschlüsselwerten enthalten.

Sie können auch die Anzahl der Partitionen bestimmen, die zusammen mit der Sammlung erstellt werden sollen. Dies gilt nur, wenn Sie ein skalares Feld als Partitionsschlüssel festgelegt haben.

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
}"

Filterungsbedingung erstellen

Wenn Sie ANN-Suchen in einer Sammlung mit aktivierter Partitionsschlüssel-Funktion durchführen, müssen Sie einen Filterausdruck mit dem Partitionsschlüssel in die Suchanfrage aufnehmen. Im Filterausdruck können Sie den Wert des Partitionsschlüssels innerhalb eines bestimmten Bereichs einschränken, so dass Milvus den Suchbereich auf die entsprechenden Partitionen einschränkt.

Bei der Durchführung von Löschvorgängen ist es ratsam, einen Filterausdruck zu verwenden, der einen einzelnen Partitionsschlüssel angibt, um einen effizienteren Löschvorgang zu erreichen. Dieser Ansatz beschränkt den Löschvorgang auf eine bestimmte Partition, wodurch die Schreibverstärkung während der Verdichtung reduziert und Ressourcen für die Verdichtung und Indizierung gespart werden.

Die folgenden Beispiele demonstrieren die Partition-Key-basierte Filterung auf der Grundlage eines bestimmten Partition-Key-Werts und eines Satzes von Partition-Key-Werten.

# 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>'

Sie müssen partition_key durch den Namen des Feldes ersetzen, das als Partitionsschlüssel bezeichnet wird.

Partition Key Isolation verwenden

Im Multi-Tenancy-Szenario können Sie das skalare Feld, das sich auf Tenant-Identitäten bezieht, als Partitionsschlüssel festlegen und einen Filter basierend auf einem bestimmten Wert in diesem skalaren Feld erstellen. Um die Suchleistung in ähnlichen Szenarien weiter zu verbessern, führt Milvus die Funktion "Partition Key Isolation" ein.

Partition Key Isolation Partitionsschlüssel-Isolierung

Wie in der obigen Abbildung dargestellt, gruppiert Milvus Entitäten auf der Grundlage des Partitionsschlüsselwerts und erstellt für jede dieser Gruppen einen eigenen Index. Beim Empfang einer Suchanfrage sucht Milvus den Index auf der Grundlage des in der Filterbedingung angegebenen Partitionsschlüsselwerts und schränkt den Suchbereich auf die im Index enthaltenen Entitäten ein, wodurch das Scannen irrelevanter Entitäten während der Suche vermieden und die Suchleistung erheblich gesteigert wird.

Sobald Sie die Partitionsschlüssel-Isolierung aktiviert haben, müssen Sie nur einen bestimmten Wert in den Partitionsschlüssel-basierten Filter aufnehmen, damit Milvus den Suchbereich innerhalb der Entitäten, die im Index enthalten sind und übereinstimmen, einschränken kann.

Derzeit gilt die Partitionsschlüssel-Isolationsfunktion nur für Suchen, bei denen der Indextyp auf HNSW eingestellt ist.

Aktivieren der Partitionsschlüssel-Isolierung

Die folgenden Codebeispiele zeigen, wie die Partition Key Isolation aktiviert werden kann.

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
}"

Sobald Sie die Partitionsschlüssel-Isolierung aktiviert haben, können Sie den Partitionsschlüssel und die Anzahl der Partitionen wie unter Partitionsnummern festlegen beschrieben festlegen. Beachten Sie, dass der Partitionsschlüssel-basierte Filter nur einen bestimmten Partitionsschlüsselwert enthalten sollte.