• Sobre a Milvus
  • Começar
  • Conceitos
  • Guia do Utilizador
  • Importação de dados
  • Ferramentas de IA
  • Guia de Administração
  • Ferramentas
  • Integrações
  • Tutoriais
  • Perguntas frequentes
  • API Reference

Inserir ou atualizar entidades

A operação « upsert » oferece uma forma prática de inserir ou atualizar entidades numa coleção.

Visão geral

Pode utilizar « upsert » para inserir uma nova entidade ou atualizar uma já existente, dependendo se a chave primária fornecida no pedido de «upsert» existe na coleção. Se a chave primária não for encontrada, ocorre uma operação de inserção. Caso contrário, será realizada uma operação de atualização. As atualizações parciais em coleções « autoID » constituem uma exceção: atualizam apenas entidades existentes, conforme descrito abaixo.

Um upsert no Milvus funciona no modo de substituição ou de fusão.

Upsert no modo de substituição

Uma solicitação de « upsert » que funciona no modo de substituição combina uma inserção e uma eliminação. Quando é recebida uma solicitação de « » para uma entidade existente, o Milvus insere os dados contidos na carga útil da solicitação e, ao mesmo tempo, elimina a entidade existente com a chave primária original especificada nos dados.

Upsert In Override Mode Upsert no modo de substituição

Se a coleção de destino tiver o « autoID » ativado no seu campo primário, a solicitação « upsert » deve, ainda assim, incluir a chave primária da entidade de destino. O Milvus utiliza a chave primária fornecida para localizar a entidade a substituir e gera uma nova chave primária para os dados contidos na carga útil da solicitação antes de os inserir.

No caso de campos com « nullable » ativado, pode omiti-los na solicitação « upsert » se não necessitarem de quaisquer atualizações.

Upsert no modo de fusãoCompatible with Milvus v2.6.2+

Utilize o modo de fusão para atualizar campos específicos de uma entidade existente, mantendo os restantes campos inalterados.

Upsert In Merge Mode Upsert no modo de fusão

Defina « partial_update=True » e indique a chave primária e os campos que pretende atualizar.

O Milvus recupera a entidade existente com uma consulta de consistência forte, funde as suas alterações com os dados armazenados, insere a entidade fundida e elimina a entidade antiga.

Se a chave primária não existir, o resultado depende de se a opção « autoID » estiver ativada:

  • Com a opção « autoID » desativada, o Milvus tenta inserir uma nova entidade com a chave primária que forneceu. O pedido é bem-sucedido se cumprir os requisitos normais de inserção. Se faltar um campo obrigatório, o pedido falha com um erro de campo em falta. Os campos nulos e os campos com valores predefinidos podem ser omitidos, tal como numa inserção normal.
  • Com o « autoID » ativado, todas as chaves primárias na solicitação têm de existir já. O Milvus rejeita a solicitação se faltar alguma chave primária, mesmo que forneça todos os campos necessários para a inserção. Para entidades existentes, o modo de fusão mantém a chave primária inalterada.

Se uma atualização parcial falhar com um erro de campo em falta, verifique se a entidade de destino existe. Sem uma entidade existente, o Milvus não consegue recuperar os valores dos campos que omitiu.

Para novas entidades, utilize « insert » ou um «upsert» no modo de substituição. Utilize o modo de fusão para atualizações subsequentes de campos individuais.

Para campos « ARRAY », o modo de fusão suporta dois operadores no Milvus v2.6.17 e versões posteriores: « ARRAY_APPEND » e « ARRAY_REMOVE ». Estes operadores permitem-lhe acrescentar elementos ou remover elementos correspondentes de um campo « ARRAY » existente, sem ter de consultar primeiro a entidade para recuperar o seu valor atual. Para mais detalhes, consulte «Upsert de campos ARRAY no modo de fusão».

Comportamentos do Upsert: notas especiais

Existem várias notas especiais que deve ter em conta antes de utilizar a funcionalidade de fusão. Os casos seguintes partem do princípio de que tem uma coleção com dois campos escalares denominados title e issue, juntamente com uma chave primária id e um campo vetorial denominado vector.

  • Atualizar ou inserir campos com a opção « nullable » ativada.

    Suponha que o campo issue possa ser nulo. Ao realizar um upsert nestes campos, tenha em atenção que:

    • Se omitir o campo « issue » na solicitação « upsert » e desativar « partial_update », o campo « issue » será atualizado para « null », em vez de manter o seu valor original.

    • Para preservar o valor original do campo issue, é necessário ativar partial_update e omitir o campo issue ou incluir o campo issue com o seu valor original na solicitação upsert.

  • Chaves de «upsert» no campo dinâmico.

    Suponha que tenha ativado a chave dinâmica na coleção de exemplo e que os pares chave-valor no campo dinâmico de uma entidade sejam semelhantes a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Ao realizar um upsert na entidade com chaves como author, year ou tags, ou ao adicionar outras chaves, tenha em atenção que:

    • Se efetuar um «upsert» com partial_update desativado, o comportamento predefinido é a substituição. Isto significa que o valor do campo dinâmico será substituído por todos os campos não definidos no esquema incluídos no pedido e pelos respetivos valores.

      Por exemplo, se os dados incluídos na solicitação forem {"author": "Jane", "genre": "fantasy"}, os pares chave-valor no campo dinâmico da entidade de destino serão atualizados para esses valores.

    • Se efetuar um «upsert» com a opção « partial_update » ativada, o comportamento predefinido é a fusão. Isto significa que o valor do campo dinâmico será fundido com todos os campos não definidos no esquema incluídos no pedido e os respetivos valores.

      Por exemplo, se os dados incluídos na solicitação forem {"author": "John", "year": 2020, "tags": ["fiction"]}, os pares chave-valor no campo dinâmico da entidade de destino passarão a ser {"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"} após a operação de upsert.

  • Upsert de um campo JSON.

    Suponha que a coleção de exemplo tenha um campo JSON definido pelo esquema denominado extras e que os pares chave-valor neste campo JSON de uma entidade sejam semelhantes a {"author": "John", "year": 2020, "tags": ["fiction"]}.

    Ao realizar um upsert no campo extras de uma entidade com dados JSON modificados, tenha em atenção que o campo JSON é tratado como um todo, não sendo possível atualizar chaves individuais de forma seletiva. Por outras palavras, o campo JSON NÃO suporta o upsert no modo de fusão.

  • Efetuarum «upsert» num campo « ARRAY ».

    Por predefinição, um campo « ARRAY » no modo de fusão segue a semântica REPLACE: o valor incluído no pedido substitui a matriz existente. Para atualizações mais detalhadas, o Milvus v2.6.17 e versões posteriores também suportam dois operadores:

    • ARRAY_APPEND acrescenta os elementos da carga útil da solicitação ao array existente.

    • ARRAY_REMOVE remove todos os elementos da matriz existente que correspondam a um valor na carga útil do pedido.

    Para a sintaxe dos operadores, os tipos de elementos suportados e outras restrições, consulte «Upsert de campos ARRAY no modo de fusão».

  • Upsert de um campo StructArray.

    A inserção/atualização de um campo StructArray numa entidade sobrescreve o valor do campo. Para tal, é necessário fornecer uma lista de dicionários, cada um dos quais contém todos os subcampos definidos no esquema da estrutura, mesmo quando a inserção/atualização é efetuada no modo de fusão.

    Para mais detalhes, consulte «Upsert de um campo StructArray no modo de fusão».

Limites e restrições

Com base no conteúdo acima, existem vários limites e restrições a seguir:

  • A solicitação « upsert » deve incluir sempre as chaves primárias das entidades de destino, mesmo quando a opção « autoID » está ativada. Para coleções « autoID », o tratamento da chave primária depende do modo de «upsert»:

    • No modo de substituição, a chave primária identifica a entidade existente a substituir, e o Milvus gera uma nova chave primária para a entidade de substituição.

    • No modo de fusão, a chave primária identifica a entidade existente a atualizar e permanece inalterada. Se a chave primária não existir, a solicitação falha em vez de inserir uma nova entidade.

  • A coleção de destino deve estar carregada e disponível para consultas.

  • Todos os campos especificados na solicitação devem existir no esquema da coleção de destino.

  • Os valores de todos os campos especificados na solicitação devem corresponder aos tipos de dados definidos no esquema.

  • Para qualquer campo derivado de outro através de funções, o Milvus removerá o campo derivado durante a operação «upsert» para permitir o recálculo.

Upsert de entidades numa coleção

Nesta secção, iremos realizar um upsert de entidades numa coleção denominada my_collection. Esta coleção possui apenas dois campos, denominados id, vector, title e issue. O campo id é o campo primário, enquanto os campos title e issue são campos escalares.

As três entidades, caso existam na coleção, serão substituídas pelas incluídas no pedido 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,
#         ]
#     }
# }

Inserir ou atualizar entidades numa partição

Também é possível realizar um upsert de entidades numa partição especificada. Os trechos de código seguintes pressupõem que existe uma partição chamada PartitionA na sua coleção.

As três entidades, caso existam na partição, serão substituídas pelas incluídas na solicitação.

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

Inserir ou atualizar entidades no modo de fusãoCompatible with Milvus v2.6.2+

O exemplo seguinte atualiza apenas o campo « issue » das entidades com as chaves primárias « 1 » e « 2 » em « my_collection ». Antes de o executar, certifique-se de que ambas as entidades já existem. Os restantes campos mantêm os seus valores atuais.

Ao realizar um «upsert» no modo de fusão, certifique-se de que as entidades envolvidas no pedido têm o mesmo conjunto de campos. Suponha que existem duas ou mais entidades a serem submetidas a um «upsert», conforme mostrado no seguinte fragmento de código; é importante que incluam campos idênticos para evitar erros e manter a integridade dos dados.

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 no modo de fusãoCompatible with Milvus 2.6.17+

Antes do Milvus v2.6.17, a atualização de parte de um campo ` ARRAY ` exigia um fluxo de leitura-modificação-gravação do lado do cliente: consultar o array existente, alterá-lo no código da aplicação e realizar o upsert do valor de substituição completo. Os operadores de atualização parcial (ARRAY_APPEND e ARRAY_REMOVE) permitem enviar apenas os elementos a acrescentar ou remover, o que reduz a lógica do lado do cliente e evita a leitura adicional antes do «upsert».

Suponha que a entidade com a chave primária 1 já tenha tags = ["new", "trial"]. Antes dos operadores de atualização parcial, adicionar o elemento "premium" a um array exigia a inserção com atualização do array de substituição 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

Com ` ARRAY_APPEND`, basta enviar apenas o elemento a adicionar:

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

Com « ARRAY_REMOVE », basta enviar apenas o elemento correspondente a remover:

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

Ao atribuir qualquer um dos operadores a um campo através de field_ops, a semântica de atualização parcial é ativada implicitamente. Por conseguinte, não é necessário passar partial_update=True juntamente com field_ops.

Limites

  • Os valores da carga útil devem corresponder ao element_type do campo de destino ARRAY. Por exemplo, se o campo de destino for ARRAY<VARCHAR>, a carga útil deve conter valores de cadeia de caracteres.

  • No Milvus v2.6.17 e versões posteriores, ARRAY_APPEND e ARRAY_REMOVE suportam campos ARRAY cujo element_type seja BOOL, INT8, INT16, INT32, INT64, FLOAT, DOUBLE ou VARCHAR.

  • Após uma operação « ARRAY_APPEND », o comprimento da matriz resultante não deve exceder o valor definido no campo « max_capacity ».

  • As operações «upsert» simultâneas na mesma entidade não são atómicas entre pedidos. Se dois pedidos atualizarem o mesmo campo « ARRAY » ao mesmo tempo, a gravação posterior pode sobrescrever a anterior. Utilize a coordenação ao nível da aplicação se precisar de preservar todas as alterações simultâneas.

Exemplo

O exemplo seguinte utiliza uma pequena coleção users com uma chave primária pk, um campo tags do tipo ARRAY<VARCHAR> e um campo vetorial embedding. Primeiro, insere duas entidades com valores iniciais tags e, em seguida, utiliza ARRAY_APPEND e ARRAY_REMOVE para mostrar como cada operador altera o array armazenado.

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 do campo StructArray no modo de fusão

A inserção ou atualização de um campo StructArray numa entidade sobrescreve o valor do campo. Isso significa que é necessário incluir todos os subcampos definidos no esquema da estrutura ao inserir ou atualizar um campo StructArray.

O exemplo seguinte demonstra como realizar um upsert no campo « chunks » no modo de fusão, um campo StructArray com 6 subcampos. Quando a operação estiver concluída, o campo « chunks » da entidade com o id 1 é definido como a matriz com as estruturas de dois elementos fornecidas na solicitação.

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