Операция «Upsert» с сущностями
Операция « upsert » предоставляет удобный способ вставки или обновления сущностей в коллекции.
Обзор
Вы можете использовать операцию « upsert » для вставки нового объекта или обновления существующего, в зависимости от того, существует ли в коллекции первичный ключ, указанный в запросе «upsert». Если первичный ключ не найден, выполняется операция вставки. В противном случае выполняется операция обновления. Частичные обновления в коллекциях типа « autoID » являются исключением: они обновляют только существующие объекты, как описано ниже.
Операция upsert в Milvus работает либо в режиме перезаписи, либо в режиме слияния.
Операция «upsert» в режиме перезаписи
Запрос «upsert», работающий в режиме перезаписи, сочетает в себе операции вставки и удаления. При получении запроса « upsert » для существующего объекта Milvus вставляет данные, содержащиеся в полезенном грузе запроса, и одновременно удаляет существующий объект с исходным первичным ключом, указанным в данных.
Upsert в режиме перезаписи
Если в целевой коллекции для основного поля включена функция « autoID », запрос « upsert » все равно должен содержать первичный ключ целевого объекта. Milvus использует предоставленный первичный ключ для поиска объекта, который необходимо заменить, и генерирует новый первичный ключ для данных, содержащихся в полезной нагрузке запроса, перед их вставкой.
Поля, для которых включена функция « nullable », можно опустить в запросе ` upsert `, если они не требуют обновления.
Upsert в режиме слиянияCompatible with Milvus v2.6.2+
Вы также можете использовать флаг partial_update, чтобы запрос на обновление или вставку работал в режиме слияния. Это позволяет включать в тело запроса только те поля, которые требуют обновления.
Upsert в режиме слияния
Для выполнения слияния установите флаг ` partial_update ` в значение ` True ` в запросе ` upsert `, указав при этом первичный ключ и поля, которые необходимо обновить, с их новыми значениями.
При получении такого запроса Milvus выполняет запрос с жесткой согласованностью для извлечения сущности, обновляет значения полей на основе данных в запросе, вставляет измененные данные, а затем удаляет существующую сущность с исходным первичным ключом, переданным в запросе.
Для коллекции с включенным режимом слияния ( autoID ) режим слияния сохраняет первичный ключ, указанный в запросе, вместо генерации нового. Это отличается от режима переопределения (override mode), в котором Milvus генерирует новый первичный ключ для заменяемого объекта. Первичный ключ в запросе в режиме слияния должен идентифицировать существующий объект; в противном случае Milvus отклоняет запрос вместо вставки нового объекта.
Для полей типа « ARRAY » в режиме слияния в Milvus v2.6.17 и более поздних версиях поддерживаются два оператора: « ARRAY_APPEND » и « ARRAY_REMOVE ». Эти операторы позволяют добавлять элементы в существующее поле « ARRAY » или удалять из него соответствующие элементы без предварительного запроса к сущности для получения её текущего значения. Подробности см. в разделе «Upsert полей ARRAY в режиме слияния».
Поведение операции «Upsert»: особые замечания
Перед использованием функции слияния следует учесть несколько особых моментов. В следующих примерах предполагается, что у вас есть коллекция с двумя скалярными полями с именами title и issue, а также первичным ключом id и векторным полем vector.
Обработка полей с включенной функцией «
nullable».Предположим, что поле
issueможет принимать значение null. При выполнении операции upsert для этих полей обратите внимание на следующее:Если вы опустите поле `
issue` в запросе `upsert` и отключите `partial_update`, поле `issue` будет обновлено до значения `null`, а не сохранит своё исходное значение.Чтобы сохранить исходное значение поля
issue, необходимо либо включить параметрpartial_updateи опустить полеissue, либо включить полеissueс его исходным значением в запросupsert.
Ключи для операции «Upsert» в динамическом поле.
Предположим, что вы включили динамический ключ в коллекции из примера, и пары «ключ-значение» в динамическом поле сущности выглядят примерно так:
{"author": "John", "year": 2020, "tags": ["fiction"]}.При выполнении операции upsert для сущности с ключами, такими как
author,yearилиtags, либо при добавлении других ключей, обратите внимание на следующее:Если вы выполняете операцию upsert с отключенным параметром
partial_update, по умолчанию происходит перезапись. Это означает, что значение динамического поля будет перезаписано всеми полями, не определёнными в схеме, включёнными в запрос, и их значениями.Например, если данные, включённые в запрос, имеют вид
{"author": "Jane", "genre": "fantasy"}, пары «ключ-значение» в динамическом поле целевого объекта будут обновлены в соответствии с ними.Если вы выполняете операцию upsert с включенным параметром `
partial_update`, по умолчанию происходит слияние. Это означает, что значение динамического поля будет объединено со всеми полями, не определёнными в схеме, включёнными в запрос, и их значениями.Например, если данные, включённые в запрос, имеют вид
{"author": "John", "year": 2020, "tags": ["fiction"]}, то после операции «upsert» пары «ключ-значение» в динамическом поле целевого объекта примут вид{"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"}.
Операция upsert для поля JSON.
Предположим, что в примере коллекции имеется поле JSON, определённое схемой, с именем
extras, а пары «ключ-значение» в этом поле JSON сущности выглядят примерно так:{"author": "John", "year": 2020, "tags": ["fiction"]}.При выполнении операции «upsert» для поля
extrasсущности с измененными данными JSON обратите внимание, что поле JSON рассматривается как единое целое, и вы не можете выборочно обновлять отдельные ключи. Другими словами, поле JSON НЕ поддерживает операцию «upsert» в режиме слияния.Операция«upsert» для поля «
ARRAY».По умолчанию поле
ARRAYв режиме слияния следует семантике REPLACE: значение, переданное в запросе, перезаписывает существующий массив. Для более тонкого управления обновлениями Milvus версии 2.6.17 и выше также поддерживает два оператора:ARRAY_APPENDдобавляет элементы из полезной нагрузки запроса к существующему массиву.ARRAY_REMOVEудаляет из существующего массива все элементы, которые совпадают со значением в полезных данных запроса.
Синтаксис операторов, поддерживаемые типы элементов и другие ограничения см. в разделе «Upsert полей ARRAY в режиме слияния».
Upsert поля StructArray.
Операция upsert для поля StructArray в сущности перезаписывает значение поля. Для этого необходимо предоставить список словарей, каждый из которых содержит все подполя, определённые в схеме структуры, даже при выполнении операции upsert в режиме слияния.
Подробности см. в разделе «Upsert-операция с полем StructArray в режиме слияния».
Ограничения и запреты
Исходя из вышеизложенного, необходимо соблюдать следующие ограничения:
Запрос «
upsert» всегда должен содержать первичные ключи целевых сущностей, даже если включена опция «autoID». Для коллекций типа «autoID» обработка первичных ключей зависит от режима обновления:В режиме перезаписи первичный ключ идентифицирует существующий объект, который будет заменен, а Milvus генерирует новый первичный ключ для заменяющего объекта.
В режиме слияния первичный ключ идентифицирует существующий объект, который необходимо обновить, и остается неизменным. Если первичный ключ не существует, запрос завершается сбоем вместо вставки нового объекта.
Целевая коллекция должна быть загружена и доступна для запросов.
Все поля, указанные в запросе, должны присутствовать в схеме целевой коллекции.
Значения всех полей, указанных в запросе, должны соответствовать типам данных, определённым в схеме.
Для любого поля, полученного из другого с помощью функций, Milvus удалит производственное поле во время операции upsert, чтобы обеспечить возможность пересчёта.
Осуществление операции «upsert» для сущностей в коллекции
В этом разделе мы будем выполнять операцию upsert сущностей в коллекцию с именем my_collection. Эта коллекция содержит только два поля: id, vector, title и issue. Поле id является первичным полем, а поля title и issue — скалярными.
Эти три сущности, если они присутствуют в коллекции, будут перезаписаны теми, которые включены в запрос 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 сущностей в раздел
Вы также можете выполнить операцию upsert для сущностей в указанном разделе. В приведенных ниже фрагментах кода предполагается, что в вашей коллекции имеется раздел с именем PartitionA.
Если эти три сущности уже существуют в разделе, они будут перезаписаны сущностями, включёнными в запрос.
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,
# ]
# }
# }
Обработка сущностей в режиме слиянияCompatible with Milvus v2.6.2+
В следующем примере кода показано, как выполнять upsert сущностей с частичным обновлением. Укажите только те поля, которые необходимо обновить, и их новые значения, а также явно укажите флаг частичного обновления.
В приведенном ниже примере поле « issue » сущностей, указанных в запросе на обновление или добавление, будет обновлено до значений, включенных в запрос.
При выполнении операции «upsert» в режиме слияния убедитесь, что сущности, участвующие в запросе, имеют одинаковый набор полей. Предположим, что необходимо выполнить операцию «upsert» для двух или более сущностей, как показано в следующем фрагменте кода; важно, чтобы они содержали идентичные поля, чтобы предотвратить ошибки и сохранить целостность данных.
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 полей ARRAY в режиме слиянияCompatible with Milvus 2.6.17+
До версии Milvus v2.6.17 для обновления части массива « ARRAY » требовался цикл «чтение-изменение-запись» на стороне клиента: запрос существующего массива, его изменение в коде приложения и операция «upsert» с полной заменой значения. Операторы частичного обновления (ARRAY_APPEND и ARRAY_REMOVE) позволяют отправлять только те элементы, которые необходимо добавить или удалить, что упрощает логику на стороне клиента и позволяет избежать лишнего чтения перед операцией upsert.
Предположим, что сущность с первичным ключом 1 уже содержит tags = ["new", "trial"]. До появления операторов частичного обновления добавление элемента "premium" в массив требовало операции upsert для всего массива:
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
С ARRAY_APPEND отправляйте только элемент, который нужно добавить:
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
С помощью ARRAY_REMOVE отправляйте только соответствующий элемент для удаления:
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
Привязка любого из этих операторов к полю с помощью field_ops неявно включает семантику частичного обновления. Поэтому вам не нужно передавать partial_update=True вместе с field_ops.
Ограничения
Значения полезных данных должны соответствовать типу
element_typeцелевого поляARRAY. Например, если целевым полем являетсяARRAY<VARCHAR>, полезные данные должны содержать строковые значения.В Milvus версии 2.6.17 и более поздних
ARRAY_APPENDиARRAY_REMOVEподдерживают поляARRAY,element_typeкоторых равныBOOL,INT8,INT16,INT32,INT64,FLOAT,DOUBLEилиVARCHAR.После операции «
ARRAY_APPEND» длина результирующего массива не должна превышать значение параметра «max_capacity» для данного поля.Одновременные операции «upsert» для одного и того же объекта не являются атомарными между запросами. Если два запроса одновременно обновляют одно и то же поле
ARRAY, более поздняя запись может перезаписать более раннюю. Если необходимо сохранить все одновременные изменения, используйте координацию на уровне приложения.
Пример
В следующем примере используется небольшая коллекция users с первичным ключом pk, полем tags типа ARRAY<VARCHAR> и векторным полем embedding. Сначала вставляются две сущности с начальными значениями tags, затем с помощью ARRAY_APPEND и ARRAY_REMOVE демонстрируется, как каждый оператор изменяет сохраненный массив.
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 поля StructArray в режиме слияния
Операция «upsert» поля StructArray в сущности перезаписывает значение поля. Это означает, что при выполнении операции «upsert» поля StructArray необходимо включить все подполя, определённые в схеме структуры.
В следующем примере показано, как выполнить операцию «upsert» для поля ` chunks ` в режиме слияния — это поле StructArray с 6 подполями. По завершении операции поле ` chunks ` сущности с id 1 будет установлено в значение массива со структурами из двух элементов, указанными в запросе.
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