Utiliser la clé de partition

La clé de partition est une solution d'optimisation de la recherche basée sur les partitions. En désignant un champ scalaire spécifique comme clé de partition et en spécifiant des conditions de filtrage basées sur la clé de partition pendant la recherche, la portée de la recherche peut être réduite à plusieurs partitions, améliorant ainsi l'efficacité de la recherche. Cet article présente l'utilisation de la clé de partition et les considérations qui s'y rapportent.

Vue d'ensemble

Dans Milvus, vous pouvez utiliser des partitions pour mettre en œuvre la ségrégation des données et améliorer les performances de recherche en limitant l'étendue de la recherche à des partitions spécifiques. Si vous choisissez de gérer les partitions manuellement, vous pouvez créer un maximum de 1 024 partitions dans une collection et insérer des entités dans ces partitions sur la base d'une règle spécifique afin de réduire l'étendue de la recherche en limitant les recherches à un nombre spécifique de partitions.

Milvus introduit la clé de partition pour vous permettre de réutiliser les partitions dans la séparation des données afin de dépasser la limite du nombre de partitions que vous pouvez créer dans une collection. Lors de la création d'une collection, vous pouvez utiliser un champ scalaire comme clé de partition. Une fois la collection prête, Milvus crée le nombre spécifié de partitions dans la collection. Lors de la réception d'une entité insérée, Milvus calcule une valeur de hachage à l'aide de la valeur de la clé de partition de l'entité, exécute une opération modulo basée sur la valeur de hachage et la propriété partitions_num de la collection pour obtenir l'ID de la partition cible et stocke l'entité dans la partition cible.

Partition Vs Partition Key Partition Vs Clé de partition

La figure suivante illustre la manière dont Milvus traite les demandes de recherche dans une collection avec ou sans l'activation de la fonction Clé de partition.

  • Si la clé de partition est désactivée, Milvus recherche les entités les plus similaires au vecteur de requête dans la collection. Vous pouvez réduire l'étendue de la recherche si vous savez quelle partition contient les résultats les plus pertinents.

  • Si la clé de partition est activée, Milvus détermine l'étendue de la recherche en fonction de la valeur de la clé de partition spécifiée dans un filtre de recherche et analyse uniquement les entités des partitions qui correspondent.

With And Without Partition Key Avec et sans clé de partition

Utilisation de la clé de partition

Pour utiliser la clé de partition, vous devez

Définir la clé de partition

Pour désigner un champ scalaire comme clé de partition, vous devez définir son attribut is_partition_key à true lorsque vous ajoutez le champ scalaire.

Lorsque vous définissez un champ scalaire comme clé de partition, les valeurs du champ ne peuvent pas être vides ou nulles.

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

Définir les numéros de partition

Lorsque vous désignez un champ scalaire dans une collection comme clé de partition, Milvus crée automatiquement 16 partitions dans la collection. Lors de la réception d'une entité, Milvus choisit une partition en fonction de la valeur de la clé de partition de cette entité et stocke l'entité dans la partition, ce qui fait que certaines ou toutes les partitions contiennent des entités ayant des valeurs de clé de partition différentes.

Vous pouvez également déterminer le nombre de partitions à créer avec la collection. Ceci n'est valable que si vous avez un champ scalaire désigné comme clé de partition.

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

Créer une condition de filtrage

Lorsque vous effectuez des recherches ANN dans une collection avec la fonctionnalité Clé de partition activée, vous devez inclure une expression de filtrage impliquant la clé de partition dans la demande de recherche. Dans l'expression de filtrage, vous pouvez restreindre la valeur de la clé de partition dans une plage spécifique afin que Milvus limite l'étendue de la recherche aux partitions correspondantes.

Lors des opérations de suppression, il est conseillé d'inclure une expression de filtrage qui spécifie une seule clé de partition afin d'obtenir une suppression plus efficace. Cette approche limite l'opération de suppression à une partition particulière, ce qui réduit l'amplification de l'écriture pendant le compactage et conserve les ressources pour le compactage et l'indexation.

Les exemples suivants illustrent le filtrage basé sur la clé de partition en fonction d'une valeur de clé de partition spécifique et d'un ensemble de valeurs de clés de partition.

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

Vous devez remplacer partition_key par le nom du champ désigné comme clé de partition.

Utiliser l'isolation de la clé de partition

Dans le scénario multi-tenant, vous pouvez désigner le champ scalaire lié aux identités des locataires comme clé de partition et créer un filtre basé sur une valeur spécifique dans ce champ scalaire. Pour améliorer encore les performances de recherche dans des scénarios similaires, Milvus introduit la fonction d'isolation de la clé de partition.

Partition Key Isolation Isolation de la clé de partition

Comme le montre la figure ci-dessus, Milvus regroupe les entités en fonction de la valeur de la clé de partition et crée un index distinct pour chacun de ces groupes. Lorsqu'il reçoit une demande de recherche, Milvus localise l'index en fonction de la valeur de la clé de partition spécifiée dans la condition de filtrage et limite la portée de la recherche aux entités incluses dans l'index, ce qui évite d'analyser des entités non pertinentes pendant la recherche et améliore considérablement les performances de la recherche.

Une fois que vous avez activé l'isolation de la clé de partition, vous devez inclure une seule valeur spécifique dans le filtre basé sur la clé de partition afin que Milvus puisse restreindre la portée de la recherche dans les entités incluses dans l'index qui correspondent.

Actuellement, la fonction d'isolation des clés de partition ne s'applique qu'aux recherches dont le type d'index est défini sur HNSW.

Activer l'isolation des clés de partition

Les exemples de code suivants montrent comment activer l'isolation des clés de partition.

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

Une fois que vous avez activé l'isolation de la clé de partition, vous pouvez toujours définir la clé de partition et le nombre de partitions comme décrit dans Définir les numéros de partition. Notez que le filtre basé sur la clé de partition ne doit inclure qu'une valeur de clé de partition spécifique.