Entitas Upsert
Operasi ` upsert ` menyediakan cara yang praktis untuk menyisipkan atau memperbarui entitas dalam sebuah koleksi.
Gambaran Umum
Anda dapat menggunakan ` upsert ` untuk menyisipkan entitas baru atau memperbarui entitas yang sudah ada, tergantung pada apakah kunci utama yang disediakan dalam permintaan `upsert` terdapat dalam koleksi. Jika kunci utama tidak ditemukan, operasi penyisipan akan dilakukan. Sebaliknya, operasi pembaruan akan dilakukan. Pembaruan parsial pada koleksi ` autoID ` merupakan pengecualian: pembaruan hanya dilakukan pada entitas yang sudah ada, seperti dijelaskan di bawah ini.
Upsert di Milvus bekerja dalam mode penggantian ( override ) atau penggabungan (merge).
Upsert dalam mode "override"
Permintaan upsert yang bekerja dalam mode "override" menggabungkan operasi penyisipan dan penghapusan. Ketika permintaan " upsert " untuk entitas yang sudah ada diterima, Milvus menyisipkan data yang terdapat dalam muatan permintaan dan menghapus entitas yang sudah ada dengan kunci utama asli yang ditentukan dalam data pada saat yang sama.
Upsert dalam Mode Override
Jika koleksi target telah mengaktifkan " autoID " pada bidang primernya, permintaan upsert tetap harus menyertakan kunci primer entitas target. Milvus menggunakan kunci primer yang disediakan untuk menemukan entitas yang akan diganti, dan menghasilkan kunci primer baru untuk data yang terdapat dalam muatan permintaan sebelum menyisipkannya.
Untuk bidang yang mengaktifkan " nullable ", Anda dapat mengabaikannya dalam permintaan " upsert " jika bidang tersebut tidak memerlukan pembaruan apa pun.
Upsert dalam mode penggabunganCompatible with Milvus v2.6.2+
Gunakan mode penggabungan (merge) untuk memperbarui bidang tertentu dari entitas yang sudah ada sambil mempertahankan bidang lainnya tetap tidak berubah.
Upsert dalam Mode Merge
Atur " partial_update=True " dan berikan kunci utama serta bidang-bidang yang ingin Anda perbarui.
Milvus mengambil entitas yang ada dengan kueri konsistensi kuat, menggabungkan perubahan Anda dengan data yang tersimpan, menyisipkan entitas yang telah digabungkan, dan menghapus entitas lama.
Jika kunci utama tidak ada, hasilnya bergantung pada apakah " autoID " diaktifkan:
- Jika "
autoID" dinonaktifkan, Milvus akan mencoba menyisipkan entitas baru dengan kunci utama yang Anda berikan. Permintaan akan berhasil jika memenuhi persyaratan penyisipan normal. Jika bidang yang diwajibkan tidak ada, permintaan akan gagal dengan kesalahan "missing-field". Bidang yang dapat bernilai null dan bidang dengan nilai default dapat diabaikan, sama seperti pada penyisipan normal. - Jika mode penggabungan (
autoID) diaktifkan, setiap kunci utama dalam permintaan harus sudah ada. Milvus akan menolak permintaan jika ada kunci utama yang hilang, bahkan jika Anda menyediakan semua bidang yang diperlukan untuk penyisipan. Untuk entitas yang sudah ada, mode penggabungan akan mempertahankan kunci utama tetap sama.
Jika pembaruan sebagian gagal dengan kesalahan "missing-field", periksa apakah entitas target sudah ada. Tanpa entitas yang sudah ada, Milvus tidak dapat mengambil nilai bidang yang Anda abaikan.
Untuk entitas baru, gunakan ` insert ` atau `upsert` dalam mode override. Gunakan mode penggabungan untuk pembaruan selanjutnya pada kolom individual.
Untuk bidang ` ARRAY `, mode penggabungan mendukung dua operator di Milvus v2.6.17 dan versi selanjutnya: ` ARRAY_APPEND ` dan ` ARRAY_REMOVE`. Operator ini memungkinkan Anda menambahkan elemen ke atau menghapus elemen yang cocok dari bidang ` ARRAY ` yang sudah ada, tanpa perlu terlebih dahulu melakukan kueri terhadap entitas untuk mengambil nilainya saat ini. Untuk detailnya, lihat "Upsert bidang ARRAY dalam mode penggabungan".
Perilaku Upsert: catatan khusus
Ada beberapa catatan khusus yang perlu Anda pertimbangkan sebelum menggunakan fitur penggabungan. Kasus-kasus berikut mengasumsikan bahwa Anda memiliki koleksi dengan dua bidang skalar bernama title dan issue, bersama dengan kunci utama id dan bidang vektor bernama vector.
Mel akukan `upsert` pada bidang dengan opsi `
nullable` diaktifkan.Misalkan bidang
issuedapat bernilai null. Saat Anda melakukan upsert pada bidang-bidang ini, perhatikan bahwa:Jika Anda mengabaikan bidang `
issue` dalam permintaan `upsert` dan menonaktifkan `partial_update`, bidang `issue` akan diperbarui menjadi `null` alih-alih mempertahankan nilainya yang asli.Untuk mempertahankan nilai asli bidang
issue, Anda perlu mengaktifkanpartial_updatedan mengabaikan bidangissue, atau menyertakan bidangissuedengan nilai aslinya dalam permintaanupsert.
Kunci upsert di bidang dinamis.
Misalkan Anda telah mengaktifkan kunci dinamis dalam koleksi contoh, dan pasangan kunci-nilai di bidang dinamis suatu entitas mirip dengan
{"author": "John", "year": 2020, "tags": ["fiction"]}.Saat Anda melakukan upsert entitas dengan kunci, seperti
author,year, atautags, atau menambahkan kunci lain, perhatikan bahwa:Jika Anda melakukan upsert dengan opsi `
partial_update` dinonaktifkan, perilaku defaultnya adalah mengganti (override). Artinya, nilai bidang dinamis akan diganti oleh semua bidang yang tidak didefinisikan dalam skema yang termasuk dalam permintaan beserta nilainya.Misalnya, jika data yang disertakan dalam permintaan adalah
{"author": "Jane", "genre": "fantasy"}, pasangan kunci-nilai di bidang dinamis entitas target akan diperbarui menjadi nilai tersebut.Jika Anda melakukan upsert dengan opsi `
partial_update` diaktifkan, perilaku defaultnya adalah penggabungan. Artinya, nilai bidang dinamis akan digabungkan dengan semua bidang yang tidak didefinisikan dalam skema yang terdapat dalam permintaan beserta nilainya.Misalnya, jika data yang disertakan dalam permintaan adalah
{"author": "John", "year": 2020, "tags": ["fiction"]}, pasangan kunci-nilai di bidang dinamis entitas tujuan akan menjadi{"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"}setelah upsert.
Melakukan upsert pada bidang JSON.
Misalkan koleksi contoh memiliki bidang JSON yang ditentukan oleh skema bernama `
extras`, dan pasangan kunci-nilai dalam bidang JSON entitas ini mirip dengan `{"author": "John", "year": 2020, "tags": ["fiction"]}`.Saat Anda melakukan upsert pada bidang
extrassuatu entitas dengan data JSON yang dimodifikasi, perhatikan bahwa bidang JSON diperlakukan sebagai satu kesatuan, dan Anda tidak dapat memperbarui kunci individu secara selektif. Dengan kata lain, bidang JSON TIDAK mendukung upsert dalam mode penggabungan.Melakukanupsert pada bidang `
ARRAY` .Secara default, bidang `
ARRAY` dalam mode penggabungan mengikuti semantik REPLACE: nilai yang dibawa dalam permintaan akan menimpa array yang ada. Untuk pembaruan yang lebih terperinci, Milvus v2.6.17 dan versi selanjutnya juga mendukung dua operator:ARRAY_APPENDmenambahkan elemen-elemen dalam muatan permintaan ke array yang ada.ARRAY_REMOVEmenghapus setiap elemen dari array yang ada yang cocok dengan nilai dalam muatan permintaan.
Untuk sintaks operator, tipe elemen yang didukung, dan batasan lainnya, lihat Upsert bidang ARRAY dalam mode penggabungan.
Melakukan Upsert pada bidang StructArray.
Melakukan upsert pada bidang StructArray dalam suatu entitas akan menimpa nilai bidang tersebut. Untuk melakukannya, Anda perlu menyediakan daftar kamus, yang masing-masing berisi semua subbidang yang didefinisikan dalam skema struct, bahkan saat Anda melakukan upsert dalam mode penggabungan.
Untuk detailnya, lihat Upsert bidang StructArray dalam mode penggabungan.
Batasan & Pembatasan
Berdasarkan konten di atas, terdapat beberapa batasan dan ketentuan yang harus dipatuhi:
Permintaan "
upsert" harus selalu menyertakan kunci utama entitas tujuan, bahkan saat "autoID" diaktifkan. Untuk koleksi "autoID", penanganan kunci utama bergantung pada mode "upsert":Dalam mode override, kunci utama mengidentifikasi entitas yang sudah ada untuk diganti, dan Milvus menghasilkan kunci utama baru untuk entitas pengganti.
Dalam mode penggabungan (merge mode), kunci utama mengidentifikasi entitas yang sudah ada untuk diperbarui dan tetap tidak berubah. Jika kunci utama tidak ada, permintaan akan gagal alih-alih menyisipkan entitas baru.
Koleksi tujuan harus sudah dimuat dan tersedia untuk kueri.
Semua bidang yang ditentukan dalam permintaan harus ada dalam skema koleksi target.
Nilai dari semua bidang yang ditentukan dalam permintaan harus sesuai dengan tipe data yang didefinisikan dalam skema.
Untuk bidang apa pun yang diturunkan dari bidang lain menggunakan fungsi, Milvus akan menghapus bidang yang diturunkan tersebut selama proses upsert agar perhitungan ulang dapat dilakukan.
Upsert entitas dalam koleksi
Pada bagian ini, kita akan melakukan upsert entitas ke dalam koleksi bernama my_collection. Koleksi ini hanya memiliki dua kolom, yaitu id, vector, title, dan issue. Kolom id adalah kolom utama, sedangkan kolom title dan issue adalah kolom skalar.
Ketiga entitas tersebut, jika ada dalam koleksi, akan diganti oleh entitas yang disertakan dalam permintaan 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 entitas dalam partisi
Anda juga dapat melakukan upsert entitas ke dalam partisi tertentu. Potongan kode berikut mengasumsikan bahwa Anda memiliki partisi bernama PartitionA dalam koleksi Anda.
Ketiga entitas tersebut, jika sudah ada di partisi, akan ditimpa oleh entitas yang disertakan dalam permintaan.
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,
# ]
# }
# }
Menambahkan atau memperbarui entitas dalam mode penggabunganCompatible with Milvus v2.6.2+
Contoh berikut hanya memperbarui bidang ` issue ` dari entitas dengan kunci utama ` 1 ` dan ` 2 ` di ` my_collection`. Sebelum menjalankannya, pastikan kedua entitas tersebut sudah ada. Bidang lainnya tetap mempertahankan nilai saat ini.
Saat melakukan upsert dalam mode merge, pastikan entitas yang terlibat dalam permintaan memiliki kumpulan bidang yang sama. Misalkan ada dua atau lebih entitas yang akan di-upsert, seperti yang ditunjukkan dalam potongan kode berikut, penting bagi entitas-entitas tersebut untuk menyertakan bidang yang identik guna mencegah kesalahan dan menjaga integritas data.
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 bidang ARRAY dalam mode penggabunganCompatible with Milvus 2.6.17+
Sebelum Milvus v2.6.17, memperbarui sebagian dari bidang ` ARRAY ` memerlukan alur baca-modifikasi-tulis di sisi klien: mengambil array yang ada, mengubahnya dalam kode aplikasi, dan melakukan `upsert` terhadap nilai pengganti secara keseluruhan. Operator pembaruan parsial (ARRAY_APPEND dan ARRAY_REMOVE) memungkinkan Anda hanya mengirim elemen yang akan ditambahkan atau dihapus, sehingga mengurangi logika di sisi klien dan menghindari pembacaan tambahan sebelum proses upsert.
Misalkan entitas dengan kunci utama ` 1 ` sudah memiliki ` tags = ["new", "trial"]`. Sebelum adanya operator pembaruan parsial, menambahkan elemen ` "premium" ` ke dalam array memerlukan proses `upsert` terhadap array pengganti secara keseluruhan:
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
Dengan ARRAY_APPEND, cukup kirim elemen yang akan ditambahkan:
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
Dengan ` ARRAY_REMOVE`, cukup kirimkan elemen yang cocok untuk dihapus:
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
Menambahkan salah satu operator ke bidang melalui field_ops secara implisit mengaktifkan semantik pembaruan parsial. Oleh karena itu, Anda tidak perlu mengirimkan partial_update=True bersamaan dengan field_ops.
Batasan
Nilai muatan (payload) harus sesuai dengan tipe data (
element_type) dari bidangARRAYyang dituju. Misalnya, jika bidang yang dituju adalahARRAY<VARCHAR>, muatan harus berisi nilai string.Di Milvus v2.6.17 dan versi selanjutnya,
ARRAY_APPENDdanARRAY_REMOVEmendukung bidangARRAYyangelement_type-nya adalahBOOL,INT8,INT16,INT32,INT64,FLOAT,DOUBLE, atauVARCHAR.Setelah operasi `
ARRAY_APPEND`, panjang array hasil tidak boleh melebihi `max_capacity` bidang tersebut.Pembaruan bersamaan (upsert) pada entitas yang sama tidak bersifat atomik antar permintaan. Jika dua permintaan memperbarui bidang
ARRAYyang sama pada saat yang sama, penulisan yang dilakukan kemudian dapat menimpa yang sebelumnya. Gunakan koordinasi tingkat aplikasi jika Anda perlu mempertahankan semua perubahan bersamaan tersebut.
Contoh
Contoh berikut menggunakan koleksi kecil ` users ` dengan kunci utama ` pk`, bidang ` tags ` bertipe ` ARRAY<VARCHAR>`, dan bidang vektor ` embedding `. Contoh ini pertama-tama menyisipkan dua entitas dengan nilai awal ` tags `, lalu menggunakan ` ARRAY_APPEND ` dan ` ARRAY_REMOVE ` untuk menunjukkan bagaimana setiap operator mengubah array yang tersimpan.
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 bidang StructArray dalam mode penggabungan
Melakukan upsert pada bidang StructArray dalam suatu entitas akan menimpa nilai bidang tersebut. Artinya, Anda perlu menyertakan semua subbidang yang didefinisikan dalam skema struct saat melakukan upsert pada bidang StructArray.
Contoh berikut menunjukkan cara melakukan `upsert` pada bidang ` chunks ` dalam mode penggabungan, yaitu bidang StructArray dengan 6 subbidang. Setelah operasi selesai, bidang ` chunks ` dari entitas dengan id 1 akan disetel ke array yang berisi struktur berelemen dua yang disertakan dalam permintaan.
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