• Acerca de Milvus
  • Empezar
  • Conceptos
  • Guía del usuario
  • Importación de datos
  • Herramientas de IA
  • Guía de administración
  • Herramientas
  • Integraciones
  • Tutoriales
  • Preguntas frecuentes
  • API Reference

Insertar o actualizar entidades

La operación « upsert » ofrece una forma cómoda de insertar o actualizar entidades en una colección.

Descripción general

Puedes utilizar « upsert » para insertar una nueva entidad o actualizar una ya existente, dependiendo de si la clave primaria proporcionada en la solicitud de «upsert» existe en la colección. Si no se encuentra la clave primaria, se lleva a cabo una operación de inserción. De lo contrario, se realizará una operación de actualización. Las actualizaciones parciales en las colecciones « autoID » son una excepción: solo actualizan las entidades existentes, tal y como se describe a continuación.

Un «upsert» en Milvus funciona en modo de sobrescritura o de fusión.

Upsert en modo «override»

Una solicitud de «upsert» que funciona en modo de sobrescritura combina una inserción y una eliminación. Cuando se recibe una solicitud de « upsert » para una entidad existente, Milvus inserta los datos contenidos en la carga útil de la solicitud y, al mismo tiempo, elimina la entidad existente con la clave primaria original especificada en los datos.

Upsert In Override Mode «Upsert» en modo de sobrescritura

Si la colección de destino tiene habilitado el « autoID » en su campo primario, la solicitud upsert debe incluir igualmente la clave primaria de la entidad de destino. Milvus utiliza la clave primaria proporcionada para localizar la entidad que se va a sustituir y genera una nueva clave primaria para los datos contenidos en la carga útil de la solicitud antes de insertarlos.

En el caso de los campos con « nullable » habilitado, puedes omitirlos en la solicitud « upsert » si no requieren ninguna actualización.

Upsert en modo de fusiónCompatible with Milvus v2.6.2+

También puede utilizar el indicador « partial_update » para que una solicitud de «upsert» funcione en modo de fusión. Esto le permite incluir en la carga útil de la solicitud únicamente los campos que necesitan actualizarse.

Upsert In Merge Mode Upsert en modo de fusión

Para realizar una fusión, establezca ` partial_update ` en ` True ` en la solicitud ` upsert `, junto con la clave primaria y los campos que se van a actualizar con sus nuevos valores.

Al recibir dicha solicitud, Milvus realiza una consulta con consistencia fuerte para recuperar la entidad, actualiza los valores de los campos basándose en los datos de la solicitud, inserta los datos modificados y, a continuación, elimina la entidad existente con la clave primaria original incluida en la solicitud.

En el caso de una colección con la opción « autoID » habilitada, el modo de fusión conserva la clave primaria proporcionada en la solicitud en lugar de generar una nueva. Esto difiere del modo de sobrescritura, en el que Milvus genera una nueva clave primaria para la entidad de sustitución. La clave primaria en una solicitud en modo de fusión debe identificar una entidad existente; de lo contrario, Milvus rechaza la solicitud en lugar de insertar una nueva entidad.

Para los campos « ARRAY », el modo de fusión admite dos operadores en Milvus v2.6.17 y versiones posteriores: « ARRAY_APPEND » y « ARRAY_REMOVE ». Estos operadores permiten añadir elementos o eliminar elementos coincidentes de un campo « ARRAY » existente, sin necesidad de consultar primero la entidad para recuperar su valor actual. Para más detalles, consulta «Upsert de campos ARRAY en modo de fusión».

Comportamientos de «Upsert»: notas especiales

Hay varias notas especiales que debe tener en cuenta antes de utilizar la función de fusión. Los siguientes casos dan por supuesto que dispone de una colección con dos campos escalares denominados title y issue, junto con una clave primaria id y un campo vectorial llamado vector.

  • Actualizar o insertar campos con la opción « nullable » activada.

    Supongamos que el campo issue puede ser nulo. Al realizar una operación «upsert» en estos campos, ten en cuenta lo siguiente:

    • Si omite el campo « issue » en la solicitud « upsert » y desactiva « partial_update », el campo « issue » se actualizará a « null » en lugar de conservar su valor original.

    • Para conservar el valor original del campo « issue », es necesario habilitar « partial_update » y omitir el campo « issue », o bien incluir el campo « issue » con su valor original en la solicitud « upsert ».

  • Claves de inserción o actualización en el campo dinámico.

    Supongamos que ha habilitado la clave dinámica en la colección de ejemplo y que los pares clave-valor del campo dinámico de una entidad son similares a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Al realizar un «upsert» de la entidad con claves como author, year o tags, o al añadir otras claves, ten en cuenta lo siguiente:

    • Si se realiza una operación «upsert» con partial_update desactivado, el comportamiento predeterminado es la sobrescritura. Esto significa que el valor del campo dinámico se sobrescribirá con todos los campos no definidos en el esquema incluidos en la solicitud y sus valores.

      Por ejemplo, si los datos incluidos en la solicitud son {"author": "Jane", "genre": "fantasy"}, los pares clave-valor del campo dinámico de la entidad de destino se actualizarán con esos valores.

    • Si realizas una operación «upsert» con la opción « partial_update » activada, el comportamiento predeterminado es la fusión. Esto significa que el valor del campo dinámico se fusionará con todos los campos no definidos en el esquema incluidos en la solicitud y sus valores.

      Por ejemplo, si los datos incluidos en la solicitud son {"author": "John", "year": 2020, "tags": ["fiction"]}, los pares clave-valor del campo dinámico de la entidad de destino pasarán a ser {"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"} tras la operación «upsert».

  • Upsert de un campo JSON.

    Supongamos que la colección de ejemplo tiene un campo JSON definido en el esquema denominado extras, y que los pares clave-valor de este campo JSON de una entidad son similares a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Al realizar un «upsert» en el campo extras de una entidad con datos JSON modificados, ten en cuenta que el campo JSON se trata como un todo y no es posible actualizar claves individuales de forma selectiva. En otras palabras, el campo JSON NO admite el «upsert» en modo de fusión.

  • Actualizar o insertar un campo « ARRAY ».

    De forma predeterminada, un campo ` ARRAY ` en modo «merge» sigue la semántica de REPLACE: el valor incluido en la solicitud sobrescribe la matriz existente. Para actualizaciones más precisas, Milvus v2.6.17 y versiones posteriores también admiten dos operadores:

    • ARRAY_APPEND añade los elementos de la carga útil de la solicitud a la matriz existente.

    • ARRAY_REMOVE elimina del array existente todos los elementos que coincidan con un valor de la carga útil de la solicitud.

    Para conocer la sintaxis de los operadores, los tipos de elementos admitidos y otras restricciones, consulta «Upsert de campos ARRAY en modo de fusión».

  • Realizar una operación «upsert» en un campo StructArray.

    Al realizar un «upsert» en un campo StructArray de una entidad, se sobrescribe el valor del campo. Para ello, debe proporcionar una lista de diccionarios, cada uno de los cuales contenga todos los subcampos definidos en el esquema de la estructura, incluso cuando realice el «upsert» en modo de fusión.

    Para obtener más información, consulta «Upsert de un campo StructArray en modo de fusión».

Límites y restricciones

Según lo expuesto anteriormente, hay varios límites y restricciones que deben tenerse en cuenta:

  • La solicitud « upsert » debe incluir siempre las claves primarias de las entidades de destino, incluso cuando esté habilitada la opción « autoID ». Para las colecciones « autoID », el manejo de la clave primaria depende del modo de «upsert»:

    • En el modo de sobrescritura, la clave primaria identifica la entidad existente que se va a sustituir, y Milvus genera una nueva clave primaria para la entidad sustitutiva.

    • En el modo de fusión, la clave primaria identifica la entidad existente que se va a actualizar y permanece sin cambios. Si la clave primaria no existe, la solicitud falla en lugar de insertar una nueva entidad.

  • La colección de destino debe estar cargada y disponible para consultas.

  • Todos los campos especificados en la solicitud deben existir en el esquema de la colección de destino.

  • Los valores de todos los campos especificados en la solicitud deben coincidir con los tipos de datos definidos en el esquema.

  • En el caso de cualquier campo derivado de otro mediante funciones, Milvus eliminará el campo derivado durante la operación «upsert» para permitir su recálculo.

Upsert de entidades en una colección

En esta sección, realizaremos un «upsert» de entidades en una colección denominada « my_collection ». Esta colección solo tiene dos campos, denominados « id », « vector », « title » y « issue ». El campo « id » es el campo primario, mientras que los campos « title » y « issue » son campos escalares.

Las tres entidades, si existen en la colección, serán sobrescritas por las incluidas en la solicitud de «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,
#         ]
#     }
# }

Insertar o actualizar entidades en una partición

También puedes realizar una operación «upsert» de entidades en una partición específica. Los siguientes fragmentos de código dan por hecho que tienes una partición llamada «PartitionA» en tu colección.

Las tres entidades, si existen en la partición, serán sustituidas por las incluidas en la solicitud.

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,
#         ]
#     }
# }

Insertar o actualizar entidades en modo de fusiónCompatible with Milvus v2.6.2+

El siguiente ejemplo de código muestra cómo realizar una operación «upsert» de entidades con actualizaciones parciales. Proporcione únicamente los campos que requieran actualización y sus nuevos valores, junto con el indicador explícito de actualización parcial.

En el siguiente ejemplo, el campo « issue » de las entidades especificadas en la solicitud de inserción o actualización se actualizará con los valores incluidos en la solicitud.

Al realizar un «upsert» en modo de fusión, asegúrate de que las entidades implicadas en la solicitud tengan el mismo conjunto de campos. Supongamos que hay dos o más entidades que se van a someter a un «upsert», tal y como se muestra en el siguiente fragmento de código; es importante que incluyan campos idénticos para evitar errores y mantener la integridad de los datos.

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 de campos ARRAY en modo «merge»Compatible with Milvus 2.6.17+

Antes de Milvus v2.6.17, la actualización de parte de un campo « ARRAY » requería un flujo de lectura-modificación-escritura del lado del cliente: consultar la matriz existente, modificarla en el código de la aplicación y realizar un «upsert» con el valor de sustitución completo. Los operadores de actualización parcial (ARRAY_APPEND y ARRAY_REMOVE) permiten enviar solo los elementos que se van a añadir o eliminar, lo que reduce la lógica del lado del cliente y evita la lectura adicional previa a la inserción o actualización.

Supongamos que la entidad con clave primaria 1 ya tiene tags = ["new", "trial"]. Antes de los operadores de actualización parcial, añadir el elemento "premium" a un array requería realizar un «upsert» del array de sustitución completo:

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, solo hay que enviar el elemento que se desea añadir:

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 », basta con enviar el elemento coincidente que se desea eliminar:

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

Al aplicar cualquiera de estos operadores a un campo mediante ` field_ops `, se habilita implícitamente la semántica de actualización parcial. Por lo tanto, no es necesario pasar ` partial_update=True ` junto con ` field_ops`.

Límites

  • Los valores de la carga útil deben coincidir con el « element_type » del campo de destino « ARRAY ». Por ejemplo, si el campo de destino es « ARRAY<VARCHAR> », la carga útil debe contener valores de cadena.

  • En Milvus v2.6.17 y versiones posteriores, ARRAY_APPEND y ARRAY_REMOVE admiten campos ARRAY cuyo element_type sea BOOL, INT8, INT16, INT32, INT64, FLOAT, DOUBLE o VARCHAR.

  • Tras una operación « ARRAY_APPEND », la longitud de la matriz resultante no debe superar el valor de « max_capacity » del campo.

  • Las operaciones «upsert» simultáneas en la misma entidad no son atómicas entre solicitudes. Si dos solicitudes actualizan el mismo campo ARRAY al mismo tiempo, la escritura posterior puede sobrescribir la anterior. Utilice la coordinación a nivel de aplicación si necesita conservar todos los cambios simultáneos.

Ejemplo

El siguiente ejemplo utiliza una pequeña colección users con una clave primaria pk, un campo tags de tipo ARRAY<VARCHAR> y un campo vectorial embedding. Primero inserta dos entidades con valores iniciales tags y, a continuación, utiliza ARRAY_APPEND y ARRAY_REMOVE para mostrar cómo cada operador modifica el array almacenado.

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 en modo «merge»

Al realizar un «upsert» en un campo StructArray de una entidad, se sobrescribe el valor del campo. Esto significa que debes incluir todos los subcampos definidos en el esquema de la estructura cuando realices un «upsert» en un campo StructArray.

El siguiente ejemplo muestra cómo realizar una operación «upsert» del campo « chunks » en modo de fusión, un campo StructArray con 6 subcampos. Cuando finaliza la operación, el campo « chunks » de la entidad con id 1 se establece en el array con las estructuras de dos elementos proporcionadas en la solicitud.

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