• Informazioni su Milvus
  • Inizia
  • Concetti
  • Guida per l'utente
  • Importazione dei dati
  • Strumenti di intelligenza artificiale
  • Guida all'amministrazione
  • Strumenti
  • Integrazioni
  • Tutorial
  • Domande frequenti
  • API Reference

Inserimento o aggiornamento di entità

L'operazione " upsert " offre un modo pratico per inserire o aggiornare entità in una raccolta.

Panoramica

È possibile utilizzare " upsert " per inserire una nuova entità o aggiornare una esistente, a seconda che la chiave primaria fornita nella richiesta "upsert" esista o meno nella collezione. Se la chiave primaria non viene trovata, viene eseguita un'operazione di inserimento. In caso contrario, verrà eseguita un'operazione di aggiornamento.

Un upsert in Milvus funziona sia in modalità di sovrascrittura che in modalità di unione.

Upsert in modalità "override"

Una richiesta di " upsert " in modalità "override" combina un'operazione di inserimento e una di eliminazione. Quando viene ricevuta una richiesta di " " per un'entità esistente, Milvus inserisce i dati contenuti nel payload della richiesta ed elimina contemporaneamente l'entità esistente con la chiave primaria originale specificata nei dati.

Upsert In Override Mode Upsert in modalità "override "

Se la collezione di destinazione ha l’ autoID abilitato sul proprio campo primario, la richiesta upsert deve comunque includere la chiave primaria dell’entità di destinazione. Milvus utilizza la chiave primaria fornita per individuare l’entità da sostituire e genera una nuova chiave primaria per i dati contenuti nel payload della richiesta prima di inserirli.

Per i campi con l’ nullable abilitato, è possibile ometterli nella richiesta upsert se non richiedono alcun aggiornamento.

Upsert in modalità mergeCompatible with Milvus v2.6.2+

È inoltre possibile utilizzare il flag ` partial_update ` per far funzionare una richiesta di upsert in modalità merge. Ciò consente di includere nel payload della richiesta solo i campi che necessitano di aggiornamento.

Upsert In Merge Mode Upsert in modalità merge

Per eseguire un merge, impostare ` partial_update ` su ` True ` nella richiesta ` upsert ` insieme alla chiave primaria e ai campi da aggiornare con i loro nuovi valori.

Alla ricezione di tale richiesta, Milvus esegue una query con forte coerenza per recuperare l’entità, aggiorna i valori dei campi in base ai dati presenti nella richiesta, inserisce i dati modificati e infine elimina l’entità esistente con la chiave primaria originale contenuta nella richiesta.

Per i campi di tipo " ARRAY ", la modalità di unione supporta due operatori in Milvus v2.6.17 e versioni successive: " ARRAY_APPEND " e " ARRAY_REMOVE". Questi operatori consentono di aggiungere elementi o rimuovere elementi corrispondenti da un campo " ARRAY " esistente, senza dover prima eseguire una query sull'entità per recuperarne il valore corrente. Per ulteriori dettagli, consultare la sezione "Upsert dei campi ARRAY in modalità di unione".

Comportamenti di Upsert: note speciali

Ci sono diverse note speciali da tenere in considerazione prima di utilizzare la funzionalità di unione. I casi seguenti presuppongono che si disponga di una collezione con due campi scalari denominati title e issue, insieme a una chiave primaria id e a un campo vettoriale denominato vector.

  • Upsert dei campi con l’opzione « nullable » abilitata.

    Supponiamo che il campo issue possa essere nullo. Quando si esegue l’upsert di questi campi, tenere presente che:

    • Se si omette il campo ` issue ` nella richiesta ` upsert ` e si disabilita ` partial_update`, il campo ` issue ` verrà aggiornato a ` null ` invece di mantenere il suo valore originale.

    • Per mantenere il valore originale del campo issue, è necessario abilitare partial_update e omettere il campo issue oppure includere il campo issue con il suo valore originale nella richiesta upsert.

  • Chiavi di upsert nel campo dinamico.

    Supponiamo di aver abilitato la chiave dinamica nella raccolta di esempio e che le coppie chiave-valore nel campo dinamico di un'entità siano simili a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Quando si esegue l’upsert dell’entità con chiavi quali author, year o tags, oppure si aggiungono altre chiavi, tenere presente che:

    • Se si esegue un'operazione di upsert con l'opzione " partial_update " disabilitata, il comportamento predefinito è la sovrascrittura. Ciò significa che il valore del campo dinamico verrà sovrascritto da tutti i campi non definiti dallo schema inclusi nella richiesta e dai relativi valori.

      Ad esempio, se i dati inclusi nella richiesta sono {"author": "Jane", "genre": "fantasy"}, le coppie chiave-valore nel campo dinamico dell’entità di destinazione verranno aggiornate in base a tali valori.

    • Se si esegue un upsert con l'opzione ` partial_update ` abilitata, il comportamento predefinito è la fusione. Ciò significa che il valore del campo dinamico si fonderà con tutti i campi non definiti dallo schema inclusi nella richiesta e con i relativi valori.

      Ad esempio, se i dati inclusi nella richiesta sono {"author": "John", "year": 2020, "tags": ["fiction"]}, le coppie chiave-valore nel campo dinamico dell’entità di destinazione diventeranno {"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"} dopo l’`upsert`.

  • Upsert di un campo JSON.

    Supponiamo che la collezione di esempio abbia un campo JSON definito dallo schema denominato extras e che le coppie chiave-valore in questo campo JSON di un'entità siano simili a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Quando si esegue l’upsert del campo extras di un’entità con dati JSON modificati, si noti che il campo JSON viene trattato nel suo insieme e non è possibile aggiornare singole chiavi in modo selettivo. In altre parole, il campo JSON NON supporta l’upsert in modalità di unione.

  • E seguire l’upsert di un campo ` ARRAY `.

    Per impostazione predefinita, un campo ARRAY in modalità merge segue la semantica REPLACE: il valore contenuto nella richiesta sovrascrive l'array esistente. Per aggiornamenti più granulari, Milvus v2.6.17 e versioni successive supportano anche due operatori:

    • ARRAY_APPEND aggiunge gli elementi presenti nel payload della richiesta all’array esistente.

    • ARRAY_REMOVE rimuove dall’array esistente ogni elemento che corrisponda a un valore presente nel payload della richiesta.

    Per la sintassi degli operatori, i tipi di elementi supportati e altri vincoli, consultare Upsert dei campi ARRAY in modalità merge.

  • Upsert di un campo StructArray.

    L'upsert di un campo StructArray in un'entità sovrascrive il valore del campo. A tal fine, è necessario fornire un elenco di dizionari, ciascuno dei quali contiene tutti i sottocampi definiti nello schema della struttura, anche quando si esegue l'upsert in modalità merge.

    Per ulteriori dettagli, consultare Upsert di un campo StructArray in modalità merge.

Limiti e restrizioni

In base a quanto sopra, è necessario rispettare diversi limiti e restrizioni:

  • La richiesta " upsert " deve sempre includere le chiavi primarie delle entità di destinazione, anche quando è abilitata l'opzione " autoID ". Per le collezioni " autoID ", le chiavi primarie nella richiesta identificano le entità esistenti da sostituire. Milvus genera nuove chiavi primarie per le entità di sostituzione inserite.

  • La collezione di destinazione deve essere caricata e disponibile per le query.

  • Tutti i campi specificati nella richiesta devono esistere nello schema della collezione di destinazione.

  • I valori di tutti i campi specificati nella richiesta devono corrispondere ai tipi di dati definiti nello schema.

  • Per qualsiasi campo derivato da un altro tramite funzioni, Milvus rimuoverà il campo derivato durante l’upsert per consentire il ricalcolo.

Upsert di entità in una collezione

In questa sezione, eseguiremo l'upsert di entità in una collezione denominata my_collection. Questa collezione presenta solo due campi, denominati id, vector, title e issue. Il campo id è il campo primario, mentre i campi title e issue sono campi scalari.

Le tre entità, se presenti nella collezione, verranno sovrascritte da quelle incluse nella richiesta di upsert.

from pymilvus import MilvusClient

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)

data=[
    {
        "id": 0, 
        "vector": [-0.619954382375778, 0.4479436794798608, -0.17493894838751745, -0.4248030059917294, -0.8648452746018911],
        "title": "Artificial Intelligence in Real Life", 
        "issue": "vol.12"
    }, {
        "id": 1, 
        "vector": [0.4762662251462588, -0.6942502138717026, -0.4490002642657902, -0.628696575798281, 0.9660395877041965], 
        "title": "Hollow Man", 
        "issue": "vol.19"
    }, {
        "id": 2, 
        "vector": [-0.8864122635045097, 0.9260170474445351, 0.801326976181461, 0.6383943392381306, 0.7563037341572827], 
        "title": "Treasure Hunt in Missouri", 
        "issue": "vol.12"
    }
]

res = client.upsert(
    collection_name='my_collection',
    data=data
)

print(res)

# Output
# {'upsert_count': 3}
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.UpsertReq;
import io.milvus.v2.service.vector.response.UpsertResp;

import java.util.*;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .token("root:Milvus")
        .build());

Gson gson = new Gson();
List<JsonObject> data = Arrays.asList(
        gson.fromJson("{\"id\": 0, \"vector\": [-0.619954382375778, 0.4479436794798608, -0.17493894838751745, -0.4248030059917294, -0.8648452746018911], \"title\": \"Artificial Intelligence in Real Life\", \"issue\": \"\vol.12\"}", JsonObject.class),
        gson.fromJson("{\"id\": 1, \"vector\": [0.4762662251462588, -0.6942502138717026, -0.4490002642657902, -0.628696575798281, 0.9660395877041965], \"title\": \"Hollow Man\", \"issue\": \"vol.19\"}", JsonObject.class),
        gson.fromJson("{\"id\": 2, \"vector\": [-0.8864122635045097, 0.9260170474445351, 0.801326976181461, 0.6383943392381306, 0.7563037341572827], \"title\": \"Treasure Hunt in Missouri\", \"issue\": \"vol.12\"}", JsonObject.class),
);

UpsertReq upsertReq = UpsertReq.builder()
        .collectionName("my_collection")
        .data(data)
        .build();

UpsertResp upsertResp = client.upsert(upsertReq);
System.out.println(upsertResp);

// Output:
//
// UpsertResp(upsertCnt=3)
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node")

const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});

data = [
    {id: 0, vector: [-0.619954382375778, 0.4479436794798608, -0.17493894838751745, -0.4248030059917294, -0.8648452746018911], title: "Artificial Intelligence in Real Life", issue: "vol.12"},
    {id: 1, vector: [0.4762662251462588, -0.6942502138717026, -0.4490002642657902, -0.628696575798281, 0.9660395877041965], title: "Hollow Man", issue: "vol.19"},
    {id: 2, vector: [-0.8864122635045097, 0.9260170474445351, 0.801326976181461, 0.6383943392381306, 0.7563037341572827], title: "Treasure Hunt in Missouri", issue: "vol.12"},
]

res = await client.upsert({
    collection_name: "my_collection",
    data: data,
})

console.log(res.upsert_cnt)

// Output
// 
// 3
// 
import (
    "context"
    "fmt"

    "github.com/milvus-io/milvus/client/v2/column"
    "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)

titleColumn := column.NewColumnString("title", []string{
    "Artificial Intelligence in Real Life", "Hollow Man", "Treasure Hunt in Missouri", 
})

issueColumn := column.NewColumnString("issue", []string{
    "vol.12", "vol.19", "vol.12"
})

_, err = client.Upsert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithInt64Column("id", []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}).
    WithFloatVectorColumn("vector", 5, [][]float32{
        {0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592},
        {0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104},
        {0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592},
    }).
    WithColumns(titleColumn, issueColumn),
)
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/upsert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
    "data": [
        {"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "title": "Artificial Intelligence in Real Life", "issue": "vol.12"},
        {"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "title": "Hollow Man", "issue": "vol.19"},
        {"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "title": "Treasure Hunt in Missouri", "issue": "vol.12"},
],
    "collectionName": "my_collection"
}'

# {
#     "code": 0,
#     "data": {
#         "upsertCount": 3,
#         "upsertIds": [
#             0,
#             1,
#             2,
#         ]
#     }
# }

Upsert di entità in una partizione

È inoltre possibile eseguire l'upsert di entità in una partizione specificata. I seguenti frammenti di codice presuppongono che nella collezione sia presente una partizione denominata PartitionA.

Le tre entità, se presenti nella partizione, verranno sovrascritte da quelle incluse nella richiesta.

data=[
    {
        "id": 10, 
        "vector": [0.06998888224297328, 0.8582816610326578, -0.9657938677934292, 0.6527905683627726, -0.8668460657158576], 
        "title": "Layour Design Reference", 
        "issue": "vol.34"
    },
    {
        "id": 11, 
        "vector": [0.6060703043917468, -0.3765080534566074, -0.7710758854987239, 0.36993888322346136, 0.5507513364206531], 
        "title": "Doraemon and His Friends", 
        "issue": "vol.2"
    },
    {
        "id": 12, 
        "vector": [-0.9041813104515337, -0.9610546012461163, 0.20033003106083358, 0.11842506351635174, 0.8327356724591011], 
        "title": "Pikkachu and Pokemon", 
        "issue": "vol.12"
    },
]

res = client.upsert(
    collection_name="my_collection",
    data=data,
    partition_name="partitionA"
)

print(res)

# Output
# {'upsert_count': 3}
import io.milvus.v2.service.vector.request.UpsertReq;
import io.milvus.v2.service.vector.response.UpsertResp;

Gson gson = new Gson();
List<JsonObject> data = Arrays.asList(
        gson.fromJson("{\"id\": 10, \"vector\": [0.06998888224297328, 0.8582816610326578, -0.9657938677934292, 0.6527905683627726, -0.8668460657158576], \"title\": \"Layour Design Reference\", \"issue\": \"vol.34\"}", JsonObject.class),
        gson.fromJson("{\"id\": 11, \"vector\": [0.6060703043917468, -0.3765080534566074, -0.7710758854987239, 0.36993888322346136, 0.5507513364206531], \"title\": \"Doraemon and His Friends\", \"issue\": \"vol.2\"}", JsonObject.class),
        gson.fromJson("{\"id\": 12, \"vector\": [-0.9041813104515337, -0.9610546012461163, 0.20033003106083358, 0.11842506351635174, 0.8327356724591011], \"title\": \"Pikkachu and Pokemon\", \"issue\": \"vol.12\"}", JsonObject.class),
);

UpsertReq upsertReq = UpsertReq.builder()
        .collectionName("my_collection")
        .partitionName("partitionA")
        .data(data)
        .build();

UpsertResp upsertResp = client.upsert(upsertReq);
System.out.println(upsertResp);

// Output:
//
// UpsertResp(upsertCnt=3)
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node")

// 6. Upsert data in partitions
data = [
    {id: 10, vector: [0.06998888224297328, 0.8582816610326578, -0.9657938677934292, 0.6527905683627726, -0.8668460657158576], title: "Layour Design Reference", issue: "vol.34"},
    {id: 11, vector: [0.6060703043917468, -0.3765080534566074, -0.7710758854987239, 0.36993888322346136, 0.5507513364206531], title: "Doraemon and His Friends", issue: "vol.2"},
    {id: 12, vector: [-0.9041813104515337, -0.9610546012461163, 0.20033003106083358, 0.11842506351635174, 0.8327356724591011], title: "Pikkachu and Pokemon", issue: "vol.12"},
]

res = await client.upsert({
    collection_name: "my_collection",
    data: data,
    partition_name: "partitionA"
})

console.log(res.upsert_cnt)

// Output
// 
// 3
// 
titleColumn = column.NewColumnString("title", []string{
    "Layour Design Reference", "Doraemon and His Friends", "Pikkachu and Pokemon", 
})
issueColumn = column.NewColumnString("issue", []string{
    "vol.34", "vol.2", "vol.12", 
})

_, err = client.Upsert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithPartition("partitionA").
    WithInt64Column("id", []int64{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}).
    WithFloatVectorColumn("vector", 5, [][]float32{
        {0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592},
        {0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104},
        {0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592},
    }).
    WithColumns(titleColumn, issueColumn),
)
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/upsert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
    "data": [
        {"id": 10, "vector": [0.06998888224297328, 0.8582816610326578, -0.9657938677934292, 0.6527905683627726, -0.8668460657158576], "title": "Layour Design Reference", "issue": "vol.34"},
        {"id": 11, "vector": [0.6060703043917468, -0.3765080534566074, -0.7710758854987239, 0.36993888322346136, 0.5507513364206531], "title": "Doraemon and His Friends", "issue": "vol.2"},
        {"id": 12, "vector": [-0.9041813104515337, -0.9610546012461163, 0.20033003106083358, 0.11842506351635174, 0.8327356724591011], "title": "Pikkachu and Pokemon", "issue": "vol.12"},
    ],
    "collectionName": "my_collection",
    "partitionName": "partitionA"
}'

# {
#     "code": 0,
#     "data": {
#         "upsertCount": 3,
#         "upsertIds": [
#             10,
#             11,
#             12,
#         ]
#     }
# }

Upsert di entità in modalità mergeCompatible with Milvus v2.6.2+

L'esempio di codice seguente illustra come eseguire l'upsert di entità con aggiornamenti parziali. È sufficiente specificare solo i campi che richiedono aggiornamenti e i relativi nuovi valori, insieme al flag esplicito di aggiornamento parziale.

Nell’esempio seguente, il campo ` issue ` delle entità specificate nella richiesta di upsert verrà aggiornato con i valori inclusi nella richiesta.

Quando si esegue un upsert in modalità merge, assicurarsi che le entità coinvolte nella richiesta abbiano lo stesso insieme di campi. Supponendo che vi siano due o più entità da sottoporre a upsert, come mostrato nel seguente frammento di codice, è importante che includano campi identici per evitare errori e mantenere l’integrità dei dati.

data=[
    {
        "id": 1,
        "issue": "vol.14"
    },
    {
        "id": 2, 
        "issue": "vol.7"
    }
]

res = client.upsert(
    collection_name="my_collection",
    data=data,
    partial_update=True
)

print(res)

# Output
# {'upsert_count': 2}
JsonObject row1 = new JsonObject();
row1.addProperty("id", 1);
row1.addProperty("issue", "vol.14");

JsonObject row2 = new JsonObject();
row2.addProperty("id", 2);
row2.addProperty("issue", "vol.7");

UpsertReq upsertReq = UpsertReq.builder()
        .collectionName("my_collection")
        .data(Arrays.asList(row1, row2))
        .partialUpdate(true)
        .build();

UpsertResp upsertResp = client.upsert(upsertReq);
System.out.println(upsertResp);

// Output:
//
// UpsertResp(upsertCnt=2)
pkColumn := column.NewColumnInt64("id", []int64{1, 2})
issueColumn = column.NewColumnString("issue", []string{
    "vol.17", "vol.7",
})

_, err = client.Upsert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithColumns(pkColumn, issueColumn).
    WithPartialUpdate(true),
)
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
const data=[
    {
        "id": 1,
        "issue": "vol.14"
    },
    {
        "id": 2, 
        "issue": "vol.7"
    }
];

const res = await client.upsert({
    collection_name: "my_collection",
    data,
    partial_update: true
});

console.log(res)

// Output
// 
// 2
// 
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

export COLLECTION_NAME="my_collection"
export UPSERT_DATA='[
  {
    "id": 1,
    "issue": "vol.14"
  },
  {
    "id": 2,
    "issue": "vol.7"
  }
]'

curl -X POST "http://localhost:19530/v2/vectordb/entities/upsert" \
  -H "Content-Type: application/json" \
  -H "Request-Timeout: 10" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d "{
    \"collectionName\": \"${COLLECTION_NAME}\",
    \"data\": ${UPSERT_DATA},
    \"partialUpdate\": true
  }"

# {
#     "code": 0,
#     "data": {
#         "upsertCount": 2,
#         "upsertIds": [
#              3,
#             12,
#         ]
#     }
# }

Upsert dei campi ARRAY in modalità mergeCompatible with Milvus 2.6.17+

Prima di Milvus v2.6.17, l’aggiornamento di una parte di un campo di tipo « ARRAY » richiedeva un flusso di lettura-modifica-scrittura lato client: interrogare l’array esistente, modificarlo nel codice dell’applicazione ed eseguire l’upsert del valore di sostituzione completo. Gli operatori di aggiornamento parziale (ARRAY_APPEND e ARRAY_REMOVE) consentono di inviare solo gli elementi da aggiungere o rimuovere, riducendo così la logica lato client ed evitando la lettura aggiuntiva prima dell’upsert.

Supponiamo che l’entità con chiave primaria 1 contenga già tags = ["new", "trial"]. Prima dell’introduzione degli operatori di aggiornamento parziale, l’aggiunta dell’elemento "premium" a un array richiedeva l’upsert dell’intero array sostitutivo:

client.upsert(
    collection_name="users",
    data=[{"pk": 1, "tags": ["new", "trial", "premium"]}],
    partial_update=True,
)
List<JsonObject> replacementData = Collections.singletonList(
        gson.fromJson("{\"pk\": 1, \"tags\": [\"new\", \"trial\", \"premium\"]}", JsonObject.class)
);

client.upsert(UpsertReq.builder()
        .collectionName("users")
        .partialUpdate(true)
        .data(replacementData)
        .build());
// nodejs
// go
# restful

Con ARRAY_APPEND, invia solo l’elemento da aggiungere:

client.upsert(
    collection_name="users",
    data=[{"pk": 1, "tags": ["premium"]}],
    field_ops={"tags": FieldOp.array_append()},
)
List<JsonObject> appendData = Collections.singletonList(
        gson.fromJson("{\"pk\": 1, \"tags\": [\"premium\"]}", JsonObject.class)
);

UpsertReq.FieldPartialUpdateOp appendTags = UpsertReq.FieldPartialUpdateOp.builder()
        .fieldName("tags")
        .opType(UpsertReq.FieldPartialUpdateOp.OpType.ARRAY_APPEND)
        .build();

client.upsert(UpsertReq.builder()
        .collectionName("users")
        .data(appendData)
        .fieldOps(Collections.singletonList(appendTags))
        .build());
// nodejs
// go
# restful

Con ` ARRAY_REMOVE`, invia solo l'elemento corrispondente da rimuovere:

client.upsert(
    collection_name="users",
    data=[{"pk": 1, "tags": ["trial"]}],
    field_ops={"tags": FieldOp.array_remove()},
)
List<JsonObject> removeData = Collections.singletonList(
        gson.fromJson("{\"pk\": 1, \"tags\": [\"trial\"]}", JsonObject.class)
);

UpsertReq.FieldPartialUpdateOp removeTags = UpsertReq.FieldPartialUpdateOp.builder()
        .fieldName("tags")
        .opType(UpsertReq.FieldPartialUpdateOp.OpType.ARRAY_REMOVE)
        .build();

client.upsert(UpsertReq.builder()
        .collectionName("users")
        .data(removeData)
        .fieldOps(Collections.singletonList(removeTags))
        .build());
// nodejs
// go
# restful

L'associazione di uno dei due operatori a un campo tramite field_ops abilita implicitamente la semantica dell'aggiornamento parziale. Pertanto, non è necessario passare partial_update=True insieme a field_ops.

Limiti

  • I valori del payload devono corrispondere all'element_type del campo di destinazione ARRAY. Ad esempio, se il campo di destinazione è ARRAY<VARCHAR>, il payload deve contenere valori di tipo stringa.

  • A partire da Milvus v2.6.17, i campi ARRAY_APPEND e ARRAY_REMOVE supportano i campi ARRAY il cui element_type è BOOL, INT8, INT16, INT32, INT64, FLOAT, DOUBLE o VARCHAR.

  • Dopo un'operazione di ARRAY_APPEND, la lunghezza dell'array risultante non deve superare il valore specificato nel campo max_capacity.

  • Gli upsert concorrenti sulla stessa entità non sono atomici tra le richieste. Se due richieste aggiornano contemporaneamente lo stesso campo ARRAY, la scrittura successiva può sovrascrivere quella precedente. Utilizzare il coordinamento a livello di applicazione se è necessario preservare tutte le modifiche concorrenti.

Esempio

L’esempio seguente utilizza una piccola collezione users con una chiave primaria pk, un campo tags di tipo ARRAY<VARCHAR> e un campo vettore embedding. Innanzitutto inserisce due entità con valori iniziali tags, quindi utilizza ARRAY_APPEND e ARRAY_REMOVE per mostrare come ciascun operatore modifichi l’array memorizzato.

from pymilvus import DataType, FieldOp, MilvusClient

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)

# 1. Create a collection with an ARRAY<VARCHAR> field
schema = client.create_schema(enable_dynamic_field=False)
schema.add_field("pk", DataType.INT64, is_primary=True)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=5)
schema.add_field(
    "tags",
    DataType.ARRAY,
    element_type=DataType.VARCHAR,
    max_capacity=8,
    max_length=32,
)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",
    metric_type="L2",
)

client.create_collection(
    collection_name="users",
    schema=schema,
    index_params=index_params
)

# 2. Seed two entities
client.insert(
    collection_name="users",
    data=[
        {"pk": 1, "embedding": [0.1, 0.2, 0.3, 0.4, 0.5], "tags": ["new"]},
        {"pk": 2, "embedding": [0.6, 0.7, 0.8, 0.9, 1.0], "tags": ["new", "trial"]},
    ],
)

# 3. Append tags without reading the existing ARRAY values
client.upsert(
    collection_name="users",
    data=[
        {"pk": 1, "tags": ["premium", "vip"]},
        {"pk": 2, "tags": ["premium"]},
    ],
    field_ops={"tags": FieldOp.array_append()},
)

res = client.query(
    collection_name="users",
    filter="pk in [1, 2]",
    output_fields=["pk", "tags"],
)
print(res)

# Example output:
# data: [
#   "{'pk': 1, 'tags': ['new', 'premium', 'vip']}",
#   "{'pk': 2, 'tags': ['new', 'trial', 'premium']}"
# ]

# 4. Remove matching tags without replacing the full ARRAY field
client.upsert(
    collection_name="users",
    data=[
        {"pk": 1, "tags": ["new"]},
        {"pk": 2, "tags": ["trial"]},
    ],
    field_ops={"tags": FieldOp.array_remove()},
)

res = client.query(
    collection_name="users",
    filter="pk in [1, 2]",
    output_fields=["pk", "tags"],
)
print(res)

# Example output:
# data: [
#   "{'pk': 1, 'tags': ['premium', 'vip']}",
#   "{'pk': 2, 'tags': ['new', 'premium']}"
# ]
// java
// nodejs
// go
# restful

Upsert del campo StructArray in modalità merge

L’upsert di un campo StructArray in un’entità sovrascrive il valore del campo. Ciò significa che è necessario includere tutti i sottocampi definiti nello schema della struttura quando si esegue l’upsert di un campo StructArray.

L'esempio seguente illustra come eseguire l'upsert del campo ` chunks ` in modalità merge, un campo StructArray con 6 sottocampi. Al termine dell'operazione, il campo ` chunks ` dell'entità con id 1 viene impostato sull'array contenente le strutture a due elementi fornite nella richiesta.

client.upsert(
    collection_name="books",
    data=[{
        "id": 1,
        "chunks": [
            {
              "text": "Use HNSW efSearch to trade recall for latency.",
              "section": "index",
              "page": 1,
              "quality_score": 0.92,
              "has_code": True,
              "emb_list_vector": [0.11, 0.21, 0.31, 0.41]
            },
            {
              "text": "Range search returns vectors within a distance boundary.",
              "section": "search",
              "page": 2,
              "quality_score": 0.86,
              "has_code": False,
              "emb_list_vector": [0.18, 0.23, 0.29, 0.36]
            }
        ]
    }],
    partial_update=True
)
// java
// nodejs
// go
# restful