Campo primario e AutoID

Ogni collezione in Milvus deve avere un campo primario per identificare in modo univoco ogni entità. Questo campo garantisce che ogni entità possa essere inserita, aggiornata, interrogata o cancellata senza ambiguità.

A seconda del caso d'uso, è possibile lasciare che Milvus generi automaticamente gli ID (AutoID) o assegnare manualmente i propri ID.

Che cos'è un campo primario?

Un campo primario funge da chiave univoca per ogni entità di una raccolta, come una chiave primaria in un database tradizionale. Milvus utilizza il campo primario per gestire le entità durante le operazioni di inserimento, upsert, cancellazione e interrogazione.

Requisiti della chiave:

  • Ogni collezione deve avere esattamente un campo primario.

  • I valori del campo primario non possono essere nulli.

  • Il tipo di dati deve essere specificato al momento della creazione e non può essere modificato in seguito.

Tipi di dati supportati

Il campo primario deve utilizzare un tipo di dati scalare supportato che possa identificare in modo univoco le entità.

Tipo di dati

Descrizione

INT64

Tipo intero a 64 bit, comunemente usato con AutoID. È l'opzione consigliata per la maggior parte dei casi d'uso.

VARCHAR

Tipo di stringa a lunghezza variabile. Si usa quando gli identificatori delle entità provengono da sistemi esterni (ad esempio, codici prodotto o ID utente). Richiede la proprietà max_length per definire il numero massimo di byte consentito per ogni valore.

Scegliere tra AutoID e ID manuali

Milvus supporta due modalità di assegnazione dei valori delle chiavi primarie.

Modalità

Descrizione

Consigliato per

AutoID

Milvus genera automaticamente identificatori univoci per le entità inserite o importate.

La maggior parte degli scenari in cui non è necessario gestire manualmente gli ID.

ID manuale

L'utente fornisce personalmente gli ID univoci durante l'inserimento o l'importazione dei dati.

Quando gli ID devono essere allineati con sistemi esterni o set di dati preesistenti.

  • Se non siete sicuri di quale modalità scegliere, iniziate con AutoID per un'ingestione più semplice e un'unicità garantita.

  • Si consiglia di affidarsi a autoId in tutti i casi, a meno che non sia utile impostare manualmente le chiavi primarie.

Avvio rapido: Usare AutoID

È possibile lasciare che Milvus gestisca automaticamente la generazione di ID.

Passo 1: Creare una collezione con AutoID

Abilitare auto_id=True nella definizione del campo primario. Milvus gestirà automaticamente la generazione degli ID.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema()

# Define primary field with AutoID enabled
schema.add_field(
    field_name="id", # Primary field name
    is_primary=True,
    auto_id=True,  # Milvus generates IDs automatically; Defaults to False
    datatype=DataType.INT64
)

# Define the other fields
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=4) # Vector field
schema.add_field(field_name="category", datatype=DataType.VARCHAR, max_length=1000) # Scalar field of the VARCHAR type

# Create the collection
if client.has_collection("demo_autoid"):
    client.drop_collection("demo_autoid")
client.create_collection(collection_name="demo_autoid", schema=schema)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.DropCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema collectionSchema = CreateCollectionReq.CollectionSchema.builder()
        .build();
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(true)
        .build());
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("embedding")
        .dataType(DataType.FloatVector)
        .dimension(4)
        .build());
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("category")
        .dataType(DataType.VarChar)
        .maxLength(1000)
        .build());

client.dropCollection(DropCollectionReq.builder()
        .collectionName("demo_autoid")
        .build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("demo_autoid")
        .collectionSchema(collectionSchema)
        .build();
client.createCollection(requestCreate);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const client = new MilvusClient({
  address: "localhost:19530",
});

// Define schema fields
const schema = [
  {
    name: "id",
    description: "Primary field",
    data_type: DataType.Int64,
    is_primary_key: true,
    autoID: true, // Milvus generates IDs automatically
  },
  {
    name: "embedding",
    description: "Vector field",
    data_type: DataType.FloatVector,
    dim: 4,
  },
  {
    name: "category",
    description: "Scalar field",
    data_type: DataType.VarChar,
    max_length: 1000,
  },
];

// Create the collection
await client.createCollection({
  collection_name: "demo_autoid",
  fields: schema,
});

// go
# restful
export SCHEMA='{
    "autoID": true,
    "fields": [
        {
            "fieldName": "id",
            "dataType": "Int64",
            "isPrimary": true,
            "elementTypeParams": {}
        },
        {
            "fieldName": "embedding",
            "dataType": "FloatVector",
            "isPrimary": false,
            "elementTypeParams": {
                "dim": "4"
            }
        },
        {
            "fieldName": "category",
            "dataType": "VarChar",
            "isPrimary": false,
            "elementTypeParams": {
                "max_length": "1000"
            }
        }
    ]
}'

curl -X POST 'http://localhost:19530/v2/vectordb/collections/create' \
-H 'Content-Type: application/json' \
-d "{
    \"collectionName\": \"demo_autoid\",
    \"schema\": $SCHEMA
}"

Passo 2: Inserire i dati

Importante: Non includere la colonna del campo primario nei dati. Milvus genera automaticamente gli ID.

data = [
    {"embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
]

res = client.insert(collection_name="demo_autoid", data=data)
print("Generated IDs:", res.get("ids"))

# Output example:
# Generated IDs: [461526052788333649, 461526052788333650]
import com.google.gson.*;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
JsonObject row1 = new JsonObject();
row1.add("embedding", gson.toJsonTree(new float[]{0.1f, 0.2f, 0.3f, 0.4f}));
row1.addProperty("category", "book");
rows.add(row1);

JsonObject row2 = new JsonObject();
row2.add("embedding", gson.toJsonTree(new float[]{0.2f, 0.3f, 0.4f, 0.5f}));
row2.addProperty("category", "toy");
rows.add(row2);

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("demo_autoid")
        .data(rows)
        .build());
System.out.printf("Generated IDs: %s\n", insertR.getPrimaryKeys());
const data = [
    {"embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
];

const res = await client.insert({
    collection_name: "demo_autoid",
    fields_data: data,
});

console.log(res);
// go
# restful
export INSERT_DATA='[
    {
        "embedding": [0.1, 0.2, 0.3, 0.4],
        "category": "book"
    },
    {
        "embedding": [0.2, 0.3, 0.4, 0.5],
        "category": "toy"
    }
]'

curl -X POST 'http://localhost:19530/v2/vectordb/entities/insert' \
-H 'Content-Type: application/json' \
-d "{
    \"collectionName\": \"demo_autoid\",
    \"data\": $INSERT_DATA
}"

Usare upsert() invece di insert() quando si lavora con entità esistenti per evitare errori di ID duplicati.

Utilizzare ID manuali

Se è necessario controllare gli ID manualmente, disabilitare AutoID e fornire i propri valori.

Passo 1: Creare un insieme senza AutoID

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema()

# Define the primary field without AutoID
schema.add_field(
    field_name="product_id",
    is_primary=True,
    auto_id=False,  # You'll provide IDs manually at data ingestion
    datatype=DataType.VARCHAR,
    max_length=100 # Required when datatype is VARCHAR
)

# Define the other fields
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=4) # Vector field
schema.add_field(field_name="category", datatype=DataType.VARCHAR, max_length=1000) # Scalar field of the VARCHAR type

# Create the collection
if client.has_collection("demo_manual_ids"):
    client.drop_collection("demo_manual_ids")
client.create_collection(collection_name="demo_manual_ids", schema=schema)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.DropCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema collectionSchema = CreateCollectionReq.CollectionSchema.builder()
        .build();
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("product_id")
        .dataType(DataType.VarChar)
        .isPrimaryKey(true)
        .autoID(false)
        .maxLength(100)
        .build());
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("embedding")
        .dataType(DataType.FloatVector)
        .dimension(4)
        .build());
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("category")
        .dataType(DataType.VarChar)
        .maxLength(1000)
        .build());

client.dropCollection(DropCollectionReq.builder()
        .collectionName("demo_manual_ids")
        .build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("demo_manual_ids")
        .collectionSchema(collectionSchema)
        .build();
client.createCollection(requestCreate);

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const client = new MilvusClient({
  address: "localhost:19530",
  username: "username",
  password: "Aa12345!!",
});

const schema = [
  {
    name: "product_id",
    data_type: DataType.VARCHAR,
    is_primary_key: true,
    autoID: false,
  },
  {
    name: "embedding",
    data_type: DataType.FLOAT_VECTOR,
    dim: 4,
  },
  {
    name: "category",
    data_type: DataType.VARCHAR,
    max_length: 1000,
  },
];

const res = await client.createCollection({
  collection_name: "demo_autoid",
  schema: schema,
});

// go
# restful
export SCHEMA='{
    "autoID": false,
    "fields": [
        {
            "fieldName": "product_id",
            "dataType": "VarChar",
            "isPrimary": true,
            "elementTypeParams": {
                "max_length": "100"
            }
        },
        {
            "fieldName": "embedding",
            "dataType": "FloatVector",
            "isPrimary": false,
            "elementTypeParams": {
                "dim": "4"
            }
        },
        {
            "fieldName": "category",
            "dataType": "VarChar",
            "isPrimary": false,
            "elementTypeParams": {
                "max_length": "1000"
            }
        }
    ]
}'

curl -X POST 'http://localhost:19530/v2/vectordb/collections/create' \
-H 'Content-Type: application/json' \
-d "{
    \"collectionName\": \"demo_manual_ids\",
    \"schema\": $SCHEMA
}"

Passo 2: Inserire i dati con i propri ID

È necessario includere la colonna del campo primario in ogni operazione di inserimento.

# Each entity must contain the primary field `product_id`
data = [
    {"product_id": "PROD-001", "embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"product_id": "PROD-002", "embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
]

res = client.insert(collection_name="demo_manual_ids", data=data)
print("Generated IDs:", res.get("ids"))

# Output example:
# Generated IDs: ['PROD-001', 'PROD-002']
import com.google.gson.*;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
JsonObject row1 = new JsonObject();
row1.addProperty("product_id", "PROD-001");
row1.add("embedding", gson.toJsonTree(new float[]{0.1f, 0.2f, 0.3f, 0.4f}));
row1.addProperty("category", "book");
rows.add(row1);

JsonObject row2 = new JsonObject();
row2.addProperty("product_id", "PROD-002");
row2.add("embedding", gson.toJsonTree(new float[]{0.2f, 0.3f, 0.4f, 0.5f}));
row2.addProperty("category", "toy");
rows.add(row2);

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("demo_manual_ids")
        .data(rows)
        .build());
System.out.printf("Generated IDs: %s\n", insertR.getPrimaryKeys());

const data = [
    {"product_id": "PROD-001", "embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"product_id": "PROD-002", "embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
];

const insert = await client.insert({
    collection_name: "demo_autoid",
    fields_data: data,
});

console.log(insert);
// go
# restful
export INSERT_DATA='[
    {
        "product_id": "PROD-001",
        "embedding": [0.1, 0.2, 0.3, 0.4],
        "category": "book"
    },
    {
        "product_id": "PROD-002",
        "embedding": [0.2, 0.3, 0.4, 0.5],
        "category": "toy"
    }
]'

# 插入数据
curl -X POST 'http://localhost:19530/v2/vectordb/entities/insert' \
-H 'Content-Type: application/json' \
-d "{
    \"collectionName\": \"demo_manual_ids\",
    \"data\": $INSERT_DATA
}"

Le vostre responsabilità:

  • Assicurarsi che tutti gli ID siano unici per tutte le entità.

  • Includere il campo primario in ogni operazione di inserimento/importazione

  • Gestire autonomamente i conflitti di ID e il rilevamento dei duplicati

Utilizzo avanzato

Migrare i dati con gli AutoID esistenti

Per preservare gli ID esistenti durante la migrazione dei dati, abilitare la proprietà allow_insert_auto_id effettuando la chiamata alter_collection_properties. Se impostata su true, Milvus accetta gli ID forniti dall'utente anche se AutoID è abilitato.

Per i dettagli sulla configurazione, fare riferimento a Modifica della raccolta.

Garantire l'unicità dell'AutoID globale in tutti i cluster

Quando si eseguono più cluster Milvus, configurare un ID cluster unico per ciascuno di essi per garantire che gli AutoID non si sovrappongano mai.

Configurazione: Modificare la configurazione common.clusterID in milvus.yaml prima di inizializzare il cluster:

common:
  clusterID: 3   # Must be unique across all clusters (Range: 0-7)

In questa configurazione, clusterID specifica l'identificatore unico usato nella generazione dell'AutoID, che va da 0 a 7 (supporta fino a otto cluster).

Milvus gestisce internamente l'inversione dei bit per consentire un'espansione futura senza sovrapposizioni di ID. Non è necessaria alcuna configurazione manuale oltre all'impostazione dell'ID del cluster.

Riferimento: Come funziona AutoID

Capire come AutoID genera internamente gli identificatori univoci può aiutare a configurare correttamente gli ID dei cluster e a risolvere i problemi relativi agli ID.

AutoID utilizza un formato strutturato a 64 bit per garantire l'unicità:

[sign_bit][cluster_id][physical_ts][logical_ts]

Segmento

Descrizione

sign_bit

Riservato per uso interno

cluster_id

Identifica quale cluster ha generato l'ID (intervallo di valori: 0-7)

physical_ts

Timestamp in millisecondi quando l'ID è stato generato

logical_ts

Contatore per distinguere gli ID creati nello stesso millisecondo

Anche quando AutoID è abilitato con VARCHAR come tipo di dati, Milvus genera comunque ID numerici. Questi sono memorizzati come stringhe numeriche con una lunghezza massima di 20 caratteri (intervallo uint64).