Konsistenz-Ebene
Als verteilte Vektordatenbank bietet Milvus mehrere Konsistenzstufen, um sicherzustellen, dass jeder Knoten oder jede Replik bei Lese- und Schreibvorgängen auf dieselben Daten zugreifen kann. Derzeit werden die Konsistenzstufen Strong, Bounded, Eventually und Session unterstützt, wobei Bounded die standardmäßig verwendete Konsistenzstufe ist.
Überblick
Milvus ist ein System, das Speicherung und Berechnung voneinander trennt. In diesem System sind DataNodes für die Persistenz der Daten verantwortlich und speichern sie schließlich in einem verteilten Objektspeicher wie MinIO/S3. QueryNodes übernehmen Berechnungsaufgaben wie die Suche. Diese Aufgaben umfassen sowohl die Verarbeitung von Stapeldaten als auch von Streaming-Daten. Einfach ausgedrückt, kann man unter Stapeldaten Daten verstehen, die bereits im Objektspeicher gespeichert wurden, während sich Streaming-Daten auf Daten beziehen, die noch nicht im Objektspeicher gespeichert wurden. Aufgrund der Netzwerklatenz verfügen die QueryNodes oft nicht über die neuesten Streaming-Daten. Ohne zusätzliche Sicherheitsvorkehrungen kann die Durchführung einer Suche direkt auf Streaming-Daten zum Verlust zahlreicher unbestätigter Datenpunkte führen, was die Genauigkeit der Suchergebnisse beeinträchtigt.
Milvus Commercial Edition ist ein System, das Speicherung und Berechnung voneinander trennt. In diesem System sind die DataNodes für die Persistenz der Daten verantwortlich und speichern sie schließlich in einem verteilten Objektspeicher wie MinIO/S3. QueryNodes übernehmen Berechnungsaufgaben wie die Suche. Diese Aufgaben umfassen sowohl die Verarbeitung von Stapeldaten als auch von Streaming-Daten. Einfach ausgedrückt, kann man unter Stapeldaten Daten verstehen, die bereits im Objektspeicher gespeichert wurden, während sich Streaming-Daten auf Daten beziehen, die noch nicht im Objektspeicher gespeichert wurden. Aufgrund der Netzwerklatenz verfügen die QueryNodes oft nicht über die aktuellsten Streaming-Daten. Ohne zusätzliche Sicherheitsvorkehrungen kann die direkte Durchführung einer Suche in Streaming-Daten zum Verlust vieler unbestätigter Datenpunkte führen, was die Genauigkeit der Suchergebnisse beeinträchtigt.
Batch-Daten und Streaming-Daten
Wie in der obigen Abbildung dargestellt, können QueryNodes nach dem Empfang einer Suchanfrage sowohl Streaming-Daten als auch Batch-Daten gleichzeitig empfangen. Aufgrund der Netzwerklatenz können die von QueryNodes erhaltenen Streaming-Daten jedoch unvollständig sein.
Um dieses Problem zu lösen, versieht Milvus jeden Datensatz in der Datenwarteschlange mit einem Zeitstempel und fügt kontinuierlich Synchronisationszeitstempel in die Datenwarteschlange ein. Wann immer ein Synchronisationszeitstempel (syncTs) empfangen wird, setzt QueryNodes diesen als ServiceTime, was bedeutet, dass QueryNodes alle Daten vor dieser ServiceTime sehen kann. Auf der Grundlage der ServiceTime kann Milvus Garantiezeitstempel (GuaranteeTs) bereitstellen, um verschiedene Benutzeranforderungen an Konsistenz und Verfügbarkeit zu erfüllen. Benutzer können QueryNodes über die Notwendigkeit informieren, Daten vor einem bestimmten Zeitpunkt in den Suchbereich aufzunehmen, indem sie GuaranteeTs in ihren Suchanfragen angeben.
ServiceTime und GuaranteeTs
Wie in der obigen Abbildung dargestellt, bedeutet GuaranteeTs, wenn es kleiner als ServiceTime ist, dass alle Daten vor dem angegebenen Zeitpunkt vollständig auf die Festplatte geschrieben wurden, so dass die QueryNodes den Suchvorgang sofort durchführen können. Wenn GuaranteeTs größer als ServiceTime ist, müssen QueryNodes warten, bis ServiceTime GuaranteeTs überschreitet, bevor sie den Suchvorgang ausführen können.
Die Benutzer müssen einen Kompromiss zwischen Abfragegenauigkeit und Abfragelatenz eingehen. Wenn Benutzer hohe Anforderungen an die Konsistenz haben und nicht auf die Abfragelatenz achten, können sie GuaranteeTs auf einen möglichst großen Wert setzen; wenn Benutzer Suchergebnisse schnell erhalten möchten und toleranter gegenüber der Abfragegenauigkeit sind, kann GuaranteeTs auf einen kleineren Wert gesetzt werden.
Veranschaulichung der Konsistenzstufen
Milvus bietet vier Arten von Konsistenzstufen mit unterschiedlichen GuaranteeTs.
Stark
Der letzte Zeitstempel wird als GuaranteeTs verwendet, und QueryNodes müssen warten, bis die ServiceTime den GuaranteeTs entspricht, bevor sie Suchanfragen ausführen.
Eventuell
Die GuaranteeTs wird auf einen extrem kleinen Wert, z. B. 1, gesetzt, um Konsistenzprüfungen zu vermeiden, so dass QueryNodes sofort Suchanfragen für alle Batch-Daten ausführen können.
Bounded Staleness
GuranteeTs wird auf einen Zeitpunkt gesetzt, der vor dem letzten Zeitstempel liegt, damit die QueryNodes Suchanfragen mit einer gewissen Toleranz gegenüber Datenverlusten durchführen können.
Sitzung
Der letzte Zeitpunkt, zu dem der Client Daten einfügt, wird als GuaranteeTs verwendet, damit QueryNodes alle vom Client eingefügten Daten durchsuchen kann.
Milvus verwendet Bounded Staleness als Standard-Konsistenzstufe. Wenn die GuaranteeTs nicht angegeben werden, wird die letzte ServiceTime als GuaranteeTs verwendet.
Konsistenzlevel festlegen
Sie können verschiedene Konsistenzstufen festlegen, wenn Sie eine Sammlung erstellen sowie Suchen und Abfragen durchführen.
Festlegen der Konsistenzstufe bei der Erstellung einer Sammlung
Beim Erstellen einer Sammlung können Sie die Konsistenzstufe für die Suchvorgänge und Abfragen innerhalb der Sammlung festlegen. Das folgende Codebeispiel setzt die Konsistenzstufe auf Stark.
client.create_collection(
collection_name="my_collection",
schema=schema,
# highlight-next
consistency_level="Strong",
)
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
// highlight-next
.consistencyLevel(ConsistencyLevel.STRONG)
.build();
client.createCollection(createCollectionReq);
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "my_id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "my_vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
},
{
"fieldName": "my_varchar",
"dataType": "VarChar",
"isClusteringKey": true,
"elementTypeParams": {
"max_length": 512
}
}
]
}'
export params='{
"consistencyLevel": "Strong"
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
Mögliche Werte für den Parameter consistency_level
sind Strong
, Bounded
, Eventually
, und Session
.
Konsistenzstufe in der Suche festlegen
Sie können jederzeit die Konsistenzstufe für eine bestimmte Suche ändern. Das folgende Codebeispiel setzt die Konsistenzstufe zurück auf "Bounded". Die Änderung gilt nur für die aktuelle Suchanfrage.
res = client.search(
collection_name="my_collection",
data=[query_vector],
limit=3,
search_params={"metric_type": "IP"},
# highlight-start
consistency_level="Bounded",
# highlight-next
)
SearchReq searchReq = SearchReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(queryVector))
.topK(3)
.searchParams(params)
.consistencyLevel(ConsistencyLevel.BOUNDED)
.build();
SearchResp searchResp = client.search(searchReq);
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"limit": 3,
"consistencyLevel": "Bounded"
}'
Dieser Parameter ist auch bei hybriden Suchen und dem Such-Iterator verfügbar. Mögliche Werte für den Parameter consistency_level
sind Strong
, Bounded
, Eventually
, und Session
.
Konsistenzstufe in der Abfrage festlegen
Sie können jederzeit die Konsistenzstufe für eine bestimmte Suche ändern. Das folgende Codebeispiel setzt die Konsistenzstufe auf den Wert Eventually. Die Einstellung gilt nur für die aktuelle Suchanfrage.
res = client.query(
collection_name="my_collection",
filter="color like \"red%\"",
output_fields=["vector", "color"],
limit=3,
# highlight-start
consistency_level="Eventually",
# highlight-next
)
QueryReq queryReq = QueryReq.builder()
.collectionName("my_collection")
.filter("color like \"red%\"")
.outputFields(Arrays.asList("vector", "color"))
.limit(3)
.consistencyLevel(ConsistencyLevel.EVENTUALLY)
.build();
QueryResp getResp = client.query(queryReq);
Dieser Parameter ist auch im Abfrage-Iterator verfügbar. Mögliche Werte für den Parameter consistency_level
sind Strong
, Bounded
, Eventually
, und Session
.