Milvus
Zilliz
Home
  • Guía del usuario
    • Insertar y eliminar
  • Home
  • Docs
  • Guía del usuario

  • Insertar y eliminar

  • Entidades Upsert

Insertar entidades

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

Visión general

Puede utilizar upsert para insertar una nueva entidad o actualizar una existente, dependiendo de si la clave primaria proporcionada en la solicitud upsert existe en la colección. Si no se encuentra la clave primaria, se realizará una operación de inserción. En caso contrario, se realizará una operación de actualización.

Un upsert en Milvus funciona en modo override o merge.

Upsert en modo override

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

Upsert In Override Mode Upsert en modo de anulación

Si la colección de destino tiene autoid habilitado en su campo primario, Milvus generará una nueva clave primaria para los datos transportados en la carga útil de la petición antes de insertarlos.

Para los campos con nullable habilitado, puede omitirlos en la solicitud upsert si no requieren ninguna actualización.

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

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

Upsert In Merge Mode Upsert en modo merge

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

Al recibir una solicitud de este tipo, Milvus realiza una consulta con coherencia 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 que figura en la solicitud.

Comportamientos Upsert: notas especiales

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

  • Campos Upsert con nullable activado.

    Supongamos que el campo issue puede ser nulo. Al upsert estos campos, tenga en cuenta que:

    • 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, debe activar partial_update y omitir el campo issue o incluir el campo issue con su valor original en la solicitud upsert.

  • Insertar claves en el campo dinámico.

    Supongamos que ha activado 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"]}.

    Cuando reinserte la entidad con claves como author, year, o tags, o añada otras claves, tenga en cuenta lo siguiente:

    • Si upsert con partial_update desactivado, el comportamiento por defecto es anular. Esto significa que el valor del campo dinámico será anulado por todos los campos no definidos por 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 a ese valor.

    • Si upsert con partial_update activado, el comportamiento por defecto es fusionar. Esto significa que el valor del campo dinámico se fusionará con todos los campos no definidos por 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 se convertirán en {"author": "Jane", "year": 2020, "tags": ["fiction"], "genre": "fantasy"} tras la inserción ascendente.

  • Upsert de un campo JSON.

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

    Cuando haga upsert en el campo extras de una entidad con datos JSON modificados, tenga en cuenta que:

    • Si upsert con partial_update desactivado, el comportamiento por defecto es anular. Esto significa que el valor del campo JSON incluido en la solicitud anulará el valor original del campo JSON de la entidad de destino.

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

    • Si upsert con partial_update activado, el comportamiento por defecto es fusionar. Esto significa que el valor del campo JSON incluido en la solicitud se fusionará con el valor original del campo JSON de la entidad de destino.

      Por ejemplo, si los datos incluidos en la solicitud son {extras: {"author": "Jane", "genre": "fantasy"}}, los pares clave-valor del campo extras de la entidad de destino se convertirán en {"author": "Jane", "year": 2020, "tags": ["fiction"], "genre": "fantasy"} después de la udpate.

Límites y restricciones

Basándose en el contenido anterior, existen varios límites y restricciones a seguir:

  • La petición upsert debe incluir siempre las claves primarias de las entidades de destino.

  • 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 petición deben coincidir con los tipos de datos definidos en el esquema.

  • Para cualquier campo derivado de otro mediante funciones, Milvus eliminará el campo derivado durante el upsert para permitir el recálculo.

Subir entidades de una colección

En esta sección, vamos a upsert entidades en una colección llamada my_collection. Esta colección sólo 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 anuladas por las que incluya la petición 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" \
-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 entidades en una partición

También puedes upsert entidades en una partición especificada. Los siguientes fragmentos de código asumen que tienes una partición llamada ParticiónA en tu colección.

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

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" \
-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 entidades en modo mergeCompatible with Milvus v2.6.2+

El siguiente ejemplo de código demuestra cómo upsert entidades con actualizaciones parciales. Proporcione sólo los campos que necesitan actualizaciones y sus nuevos valores, junto con la bandera de actualización parcial explícita.

En el siguiente ejemplo, el campo issue de las entidades especificadas en la solicitud de upsert se actualizará con los valores incluidos en la solicitud.

Al realizar una upsert en modo merge, asegúrese de que las entidades implicadas en la petición tienen el mismo conjunto de campos. Supongamos que hay dos o más entidades que se van a upsertar, 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 "Authorization: Bearer ${TOKEN}" \
  -d "{
    \"collectionName\": \"${COLLECTION_NAME}\",
    \"data\": ${UPSERT_DATA},
    \"partialUpdate\": true
  }"

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