Entitäten einfügen oder aktualisieren
Die Operation „ upsert “ bietet eine bequeme Möglichkeit, Entitäten in eine Sammlung einzufügen oder zu aktualisieren.
Übersicht
Mit „ upsert “ können Sie entweder eine neue Entität einfügen oder eine bestehende aktualisieren, je nachdem, ob der in der „Upsert“-Anfrage angegebene Primärschlüssel in der Sammlung vorhanden ist. Wird der Primärschlüssel nicht gefunden, erfolgt ein Einfügevorgang. Andernfalls wird ein Aktualisierungsvorgang durchgeführt.
Ein „Upsert“ in Milvus funktioniert entweder im Überschreib- oder im Zusammenführungsmodus.
„Upsert“ im „Override“-Modus
Eine „ upsert “-Anfrage im „Override“-Modus kombiniert einen Einfügevorgang mit einem Löschvorgang. Wenn eine „ “-Anfrage für eine vorhandene Entität eingeht, fügt Milvus die in der Anfrage-Nutzlast enthaltenen Daten ein und löscht gleichzeitig die vorhandene Entität mit dem in den Daten angegebenen ursprünglichen Primärschlüssel.
„Upsert“ im „Override“-Modus
Wenn für das Primärfeld der Zielsammlung „ autoID “ aktiviert ist, muss die „ upsert “-Anfrage dennoch den Primärschlüssel der Zielentität enthalten. Milvus verwendet den angegebenen Primärschlüssel, um die zu ersetzende Entität zu lokalisieren, und generiert vor dem Einfügen einen neuen Primärschlüssel für die in der Anforderungsnutzlast enthaltenen Daten.
Felder, für die „ nullable “ aktiviert ist, können Sie in der „ upsert “-Anfrage weglassen, sofern sie keine Aktualisierungen erfordern.
Upsert im Merge-ModusCompatible with Milvus v2.6.2+
Sie können auch das Flag „ partial_update “ verwenden, um eine Upsert-Anfrage im Merge-Modus auszuführen. Auf diese Weise können Sie nur die Felder, die aktualisiert werden müssen, in die Anfrage-Nutzlast aufnehmen.
Upsert im Merge-Modus
Um einen Merge durchzuführen, setzen Sie „ partial_update “ in der Anfrage „ upsert “ auf „ True “ – zusammen mit dem Primärschlüssel und den zu aktualisierenden Feldern sowie deren neuen Werten.
Nach Erhalt einer solchen Anfrage führt Milvus eine Abfrage mit starker Konsistenz durch, um die Entität abzurufen, aktualisiert die Feldwerte basierend auf den Daten in der Anfrage, fügt die geänderten Daten ein und löscht anschließend die vorhandene Entität mit dem in der Anfrage enthaltenen ursprünglichen Primärschlüssel.
Für „ ARRAY “-Felder unterstützt der Merge-Modus in Milvus v2.6.17 und höher zwei Operatoren: „ ARRAY_APPEND “ und „ ARRAY_REMOVE “. Mit diesen Operatoren können Sie Elemente an ein bestehendes „ ARRAY “-Feld anhängen oder übereinstimmende Elemente daraus entfernen, ohne zuvor die Entität abfragen zu müssen, um deren aktuellen Wert abzurufen. Weitere Informationen finden Sie unter „Upsert von ARRAY-Feldern im Merge-Modus“.
Verhalten bei „Upsert“: Besondere Hinweise
Es gibt einige besondere Hinweise, die Sie vor der Verwendung der Merge-Funktion beachten sollten. Die folgenden Fälle gehen davon aus, dass Sie über eine Sammlung mit zwei Skalarfeldern namens „ title “ und „ issue “ sowie einem Primärschlüssel „ id “ und einem Vektorfeld namens „ vector “ verfügen.
Felder mit aktiviertem „
nullable“per „Upsert“ aktualisieren .Angenommen, das Feld „
issue“ darf null sein. Beachten Sie beim Upsert dieser Felder Folgendes:Wenn Sie das Feld „
issue“ in der Anfrage „upsert“ weglassen und „partial_update“ deaktivieren, wird das Feld „issue“ auf „null“ aktualisiert, anstatt seinen ursprünglichen Wert beizubehalten.Um den ursprünglichen Wert des Feldes „
issue“ beizubehalten, müssen Sie entweder „partial_update“ aktivieren und das Feld „issue“ weglassen oder das Feld „issue“ mit seinem ursprünglichen Wert in die Anfrage „upsert“ aufnehmen.
Upsert-Schlüssel im dynamischen Feld.
Angenommen, Sie haben den dynamischen Schlüssel in der Beispielsammlung aktiviert, und die Schlüssel-Wert-Paare im dynamischen Feld einer Entität sehen ähnlich aus wie
{"author": "John", "year": 2020, "tags": ["fiction"]}.Wenn Sie die Entität mit Schlüsseln wie
author,yearodertagsaktualisieren oder einfügen oder andere Schlüssel hinzufügen, beachten Sie Folgendes:Wenn Sie einen „Upsert“ durchführen, während „
partial_update“ deaktiviert ist, ist das Standardverhalten das Überschreiben. Das bedeutet, dass der Wert des dynamischen Feldes durch alle in der Anfrage enthaltenen, nicht im Schema definierten Felder und deren Werte überschrieben wird.Wenn die in der Anfrage enthaltenen Daten beispielsweise „
{"author": "Jane", "genre": "fantasy"}“ lauten, werden die Schlüssel-Wert-Paare im dynamischen Feld der Zielentität entsprechend aktualisiert.Wenn Sie einen „Upsert“ mit aktivierter Option „
partial_update“ durchführen, ist das Standardverhalten das Zusammenführen. Das bedeutet, dass der Wert des dynamischen Feldes mit allen in der Anfrage enthaltenen, nicht im Schema definierten Feldern und deren Werten zusammengeführt wird.Wenn die in der Anfrage enthaltenen Daten beispielsweise
{"author": "John", "year": 2020, "tags": ["fiction"]}lauten, werden die Schlüssel-Wert-Paare im dynamischen Feld der Zielentität nach dem „Upsert“ zu{"author": "John", "year": 2020, "tags": ["fiction"], "genre": "fantasy"}.
Upsert eines JSON-Feldes.
Angenommen, die Beispielsammlung verfügt über ein schemadefiniertes JSON-Feld namens „
extras“, und die Schlüssel-Wert-Paare in diesem JSON-Feld einer Entität sehen in etwa so aus: „{"author": "John", "year": 2020, "tags": ["fiction"]}“.Wenn Sie das Feld „
extras“ einer Entität mit geänderten JSON-Daten per „Upsert“ aktualisieren, beachten Sie bitte, dass das JSON-Feld als Ganzes behandelt wird und Sie einzelne Schlüssel nicht selektiv aktualisieren können. Mit anderen Worten: Das JSON-Feld unterstützt KEIN „Upsert“ im Merge-Modus.Ein „Upsert“ eines „
ARRAY“-Feldes.Standardmäßig folgt ein „
ARRAY“-Feld im Merge-Modus der REPLACE- Semantik: Der in der Anfrage übermittelte Wert überschreibt das vorhandene Array. Für feinere Aktualisierungen unterstützt Milvus ab Version 2.6.17 außerdem zwei Operatoren:ARRAY_APPENDfügt die Elemente aus der Anfrage-Nutzlast an das vorhandene Array an.ARRAY_REMOVEentfernt jedes Element aus dem bestehenden Array, das mit einem Wert in der Anfrage-Nutzlast übereinstimmt.
Informationen zur Operatorsyntax, zu den unterstützten Elementtypen und zu weiteren Einschränkungen finden Sie unter „Upsert von ARRAY-Feldern im Merge-Modus“.
Ein StructArray-Feld „upsert“ ausführen.
Das Upsert eines „StructArray“-Feldes in einer Entität überschreibt den Feldwert. Dazu müssen Sie eine Liste von Dictionaries bereitstellen, von denen jedes alle im Struct-Schema definierten Unterfelder enthält, selbst wenn Sie das Upsert im Merge-Modus durchführen.
Weitere Informationen finden Sie unter „Upsert eines StructArray-Feldes im Merge-Modus“.
Grenzen und Einschränkungen
Aufgrund der oben genannten Inhalte gelten folgende Grenzen und Einschränkungen:
Die „
upsert“-Anfrage muss immer die Primärschlüssel der Zielentitäten enthalten, auch wenn „autoID“ aktiviert ist. Bei „autoID“-Sammlungen identifizieren die Primärschlüssel in der Anfrage die vorhandenen Entitäten, die ersetzt werden sollen. Milvus generiert neue Primärschlüssel für die eingefügten Ersatzentitäten.Die Zielsammlung muss geladen und für Abfragen verfügbar sein.
Alle in der Anfrage angegebenen Felder müssen im Schema der Zielsammlung vorhanden sein.
Die Werte aller in der Anfrage angegebenen Felder müssen mit den im Schema definierten Datentypen übereinstimmen.
Bei Feldern, die mithilfe von Funktionen aus anderen Feldern abgeleitet wurden, entfernt Milvus das abgeleitete Feld während des Upserts, um eine Neuberechnung zu ermöglichen.
Entitäten in einer Sammlung upsert
In diesem Abschnitt führen wir ein „Upsert“ von Entitäten in eine Sammlung namens „ my_collection “ durch. Diese Sammlung enthält nur zwei Felder mit den Namen „ id “, „ vector “, „ title “ und „ issue “. Das Feld „ id “ ist das Primärfeld, während die Felder „ title “ und „ issue “ Skalarfelder sind.
Sofern die drei Entitäten in der Sammlung vorhanden sind, werden sie durch die in der „Upsert“-Anfrage enthaltenen Werte überschrieben.
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,
# ]
# }
# }
Entitäten in einer Partition „upsert“
Sie können Entitäten auch in eine bestimmte Partition „upsert“-en. Die folgenden Codeausschnitte gehen davon aus, dass Sie in Ihrer Sammlung eine Partition namens „PartitionA“ haben.
Die drei Entitäten werden, sofern sie in der Partition vorhanden sind, durch die in der Anfrage enthaltenen Entitäten überschrieben.
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,
# ]
# }
# }
Entitäten im Merge-Modus einfügen oder aktualisierenCompatible with Milvus v2.6.2+
Das folgende Codebeispiel veranschaulicht, wie Entitäten mit partiellen Aktualisierungen „upsert“ werden. Geben Sie nur die Felder an, die aktualisiert werden sollen, sowie deren neue Werte, zusammen mit dem expliziten Flag für partielle Aktualisierungen.
Im folgenden Beispiel wird das Feld „ issue “ der in der Upsert-Anfrage angegebenen Entitäten auf die in der Anfrage enthaltenen Werte aktualisiert.
Stellen Sie bei der Durchführung eines „Upsert“ im Merge-Modus sicher, dass die in der Anfrage beteiligten Entitäten denselben Satz an Feldern aufweisen. Angenommen, es sollen zwei oder mehr Entitäten per „Upsert“ aktualisiert werden, wie im folgenden Codeausschnitt gezeigt, ist es wichtig, dass diese identische Felder enthalten, um Fehler zu vermeiden und die Datenintegrität zu gewährleisten.
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 von ARRAY-Feldern im Merge-ModusCompatible with Milvus 2.6.17+
Vor Milvus v2.6.17 erforderte die Aktualisierung eines Teils eines „ ARRAY “-Feldes einen clientseitigen „Read-Modify-Write“-Ablauf: Abfrage des bestehenden Arrays, Änderung im Anwendungscode und „Upsert“ des vollständigen Ersatzwerts. Mit Operatoren für Teilaktualisierungen (ARRAY_APPEND und ARRAY_REMOVE) können Sie nur die Elemente senden, die angehängt oder entfernt werden sollen. Dies reduziert die clientseitige Logik und vermeidet den zusätzlichen Lesevorgang vor dem „Upsert“.
Angenommen, die Entität mit dem Primärschlüssel ` 1 ` enthält bereits ` tags = ["new", "trial"]`. Vor der Einführung der Operatoren für partielle Aktualisierungen erforderte das Hinzufügen des Elements ` "premium" ` zu einem Array das Upsert des gesamten Ersatz-Arrays:
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
Mit „ ARRAY_APPEND “ wird nur das hinzuzufügende Element gesendet:
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
Mit „ ARRAY_REMOVE “ senden Sie nur das zu entfernende, übereinstimmende Element:
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
Das Anhängen eines der beiden Operatoren an ein Feld über ` field_ops ` aktiviert implizit die Semantik der Teilaktualisierung. Daher müssen Sie ` partial_update=True ` nicht zusätzlich zu ` field_ops` übergeben.
Einschränkungen
Die Werte der Nutzdaten müssen mit dem „
element_type“ des Zielfelds „ARRAY“ übereinstimmen. Wenn das Zielfeld beispielsweise „ARRAY<VARCHAR>“ lautet, müssen die Nutzdaten Zeichenfolgenwerte enthalten.In Milvus v2.6.17 und höher unterstützen „
ARRAY_APPEND“ und „ARRAY_REMOVE“ Felder vom Typ „ARRAY“, deren „element_type“ einer der folgenden Werte ist: „BOOL“, „INT8“, „INT16“, „INT32“, „INT64“, „FLOAT“, „DOUBLE“ oder „VARCHAR“.Nach einem „
ARRAY_APPEND“-Vorgang darf die Länge des resultierenden Arrays die „max_capacity“ des Feldes nicht überschreiten.Parallele Upserts an dieselbe Entität sind nicht über Anfragen hinweg atomar. Wenn zwei Anfragen gleichzeitig dasselbe Feld „
ARRAY“ aktualisieren, kann der spätere Schreibvorgang den früheren überschreiben. Verwenden Sie eine Koordination auf Anwendungsebene, wenn Sie alle parallelen Änderungen beibehalten müssen.
Beispiel
Das folgende Beispiel verwendet eine kleine „ users “-Sammlung mit einem Primärschlüssel „ pk “, einem Feld „ tags “ vom Typ „ ARRAY<VARCHAR> “ und einem Vektorfeld „ embedding “. Zunächst werden zwei Entitäten mit den Anfangswerten „ tags “ eingefügt, anschließend wird mithilfe von „ ARRAY_APPEND “ und „ ARRAY_REMOVE “ gezeigt, wie die einzelnen Operatoren das gespeicherte Array verändern.
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
„StructArray“-Feld im Merge-Modus upsertieren
Das Upsert eines StructArray-Feldes in einer Entität überschreibt den Feldwert. Das bedeutet, dass Sie alle im Struktur-Schema definierten Unterfelder einbeziehen müssen, wenn Sie ein StructArray-Feld upsertieren.
Das folgende Beispiel veranschaulicht, wie das Feld „ chunks “ im Merge-Modus upsertet wird – ein StructArray-Feld mit 6 Unterfeldern. Nach Abschluss des Vorgangs wird das Feld „ chunks “ der Entität mit der ID 1 auf das Array mit den in der Anfrage angegebenen Strukturen mit zwei Elementen gesetzt.
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