🚀 Prova Zilliz Cloud, la versione completamente gestita di Milvus, gratuitamente—sperimenta prestazioni 10 volte più veloci! Prova Ora>>

milvus-logo
LFAI

Utilizzo

  • Engineering
February 07, 2022
Lichen Wang

Grazie all'elaborazione unificata di batch e stream e all'architettura cloud-native, Milvus 2.0 ha posto una sfida maggiore rispetto al suo predecessore durante lo sviluppo della funzione DELETE. Grazie al suo design avanzato di disaggregazione storage-computazione e al meccanismo flessibile di pubblicazione/sottoscrizione, siamo orgogliosi di annunciare che ci siamo riusciti. In Milvus 2.0, è possibile cancellare un'entità in una determinata collezione con la sua chiave primaria, in modo che l'entità cancellata non venga più elencata nei risultati di una ricerca o di una query.

Si noti che l'operazione DELETE in Milvus si riferisce alla cancellazione logica, mentre la pulizia fisica dei dati avviene durante la Compattazione dei dati. La cancellazione logica non solo aumenta notevolmente le prestazioni di ricerca limitate dalla velocità di I/O, ma facilita anche il recupero dei dati. I dati eliminati logicamente possono essere recuperati con l'aiuto della funzione Time Travel.

Utilizzo

Proviamo innanzitutto la funzione DELETE di Milvus 2.0. (L'esempio seguente utilizza PyMilvus 2.0.0 su Milvus 2.0.0).

from pymilvus import connections, utility, Collection, DataType, FieldSchema, CollectionSchema
# Connect to Milvus
connections.connect(
    alias="default", 
    host='x.x.x.x', 
    port='19530'
)
# Create a collection with Strong Consistency level
pk_field = FieldSchema(
    name="id", 
    dtype=DataType.INT64, 
    is_primary=True, 
)
vector_field = FieldSchema(
    name="vector", 
    dtype=DataType.FLOAT_VECTOR, 
    dim=2
)
schema = CollectionSchema(
    fields=[pk_field, vector_field], 
    description="Test delete"
)
collection_name = "test_delete"
collection = Collection(
    name=collection_name, 
    schema=schema, 
    using='default', 
    shards_num=2,
    consistency_level="Strong"
)
# Insert randomly generated vectors
import random
data = [
    [i for i in range(100)],
    [[random.random() for _ in range(2)] for _ in range(100)],
]
collection.insert(data)
# Query to make sure the entities to delete exist
collection.load()
expr = "id in [2,4,6,8,10]"
pre_del_res = collection.query(
    expr,
    output_fields = ["id", "vector"]
)
print(pre_del_res)
# Delete the entities with the previous expression
collection.delete(expr)
# Query again to check if the deleted entities exist
post_del_res = collection.query(
    expr,
    output_fields = ["id", "vector"]
)
print(post_del_res)

Implementazione

In un'istanza Milvus, un nodo dati è principalmente responsabile dell'impacchettamento dei dati in streaming (registri nel log broker) come dati storici (istantanee dei registri) e del loro scarico automatico nella memoria degli oggetti. Un nodo di interrogazione esegue le richieste di ricerca sui dati completi, cioè sia sui dati in streaming che sui dati storici.

Per sfruttare al meglio la capacità di scrittura dei dati dei nodi paralleli di un cluster, Milvus adotta una strategia di sharding basata sull'hashing delle chiavi primarie per distribuire uniformemente le operazioni di scrittura ai diversi nodi worker. In altre parole, il proxy instrada i messaggi DML (Data Manipulation Language) (cioè le richieste) di un'entità verso lo stesso nodo dati e lo stesso nodo di interrogazione. Questi messaggi vengono pubblicati attraverso il canale DML e consumati dal nodo dati e dal nodo di interrogazione separatamente per fornire servizi di ricerca e interrogazione insieme.

Nodo dati

Dopo aver ricevuto i messaggi INSERT, il nodo dati inserisce i dati in un segmento in crescita, che è un nuovo segmento creato per ricevere i dati in streaming in memoria. Se il conteggio delle righe di dati o la durata del segmento in crescita raggiunge la soglia, il nodo dati lo sigilla per impedire l'arrivo di dati. Il nodo dati quindi scarica il segmento sigillato, che contiene i dati storici, nella memoria degli oggetti. Nel frattempo, il nodo dati genera un filtro bloom basato sulle chiavi primarie dei nuovi dati e lo archivia nella memoria oggetti insieme al segmento sigillato, salvando il filtro bloom come parte del registro binario delle statistiche (binlog), che contiene le informazioni statistiche del segmento.

Un filtro bloom è una struttura dati probabilistica che consiste in un lungo vettore binario e in una serie di funzioni di mappatura casuale. Può essere utilizzato per verificare se un elemento è un membro di un insieme, ma potrebbe restituire false corrispondenze positive. -- Wikipedia

Quando arrivano i messaggi di DELETE dei dati, il nodo dei dati esegue un buffer di tutti i filtri bloom nello shard corrispondente e li abbina alle chiavi primarie fornite nei messaggi per recuperare tutti i segmenti (sia quelli in crescita che quelli sigillati) che potrebbero includere le entità da cancellare. Dopo aver individuato i segmenti corrispondenti, il nodo dati li bufferizza in memoria per generare i binlog Delta per registrare le operazioni di cancellazione, e poi scarica questi binlog insieme ai segmenti nello storage degli oggetti.

Data Node Nodo dati

Poiché a uno shard è assegnato un solo canale DML, i nodi di query aggiunti al cluster non saranno in grado di sottoscrivere il canale DML. Per garantire che tutti i nodi di interrogazione possano ricevere i messaggi DELETE, i nodi dati filtrano i messaggi DELETE dal canale DML e li inoltrano al canale Delta per notificare a tutti i nodi di interrogazione le operazioni di cancellazione.

Nodo di interrogazione

Quando si carica una collezione dall'archivio oggetti, il nodo di query ottiene innanzitutto il checkpoint di ogni shard, che segna le operazioni DML dall'ultima operazione di flush. Sulla base del checkpoint, il nodo di query carica tutti i segmenti sigillati insieme ai loro filtri binlog e bloom Delta. Una volta caricati tutti i dati, il nodo di query si iscrive al DML-Channel, al Delta-Channel e al Query-Channel.

Se arrivano altri messaggi INSERT dopo che la raccolta è stata caricata in memoria, il nodo di query individua prima i segmenti in crescita in base ai messaggi e aggiorna i filtri bloom corrispondenti in memoria solo a scopo di query. Questi filtri bloom dedicati alla query non verranno scaricati nella memoria degli oggetti al termine della query.

Query Node Nodo di interrogazione

Come già detto, solo un certo numero di nodi di query può ricevere messaggi DELETE dal canale DML, il che significa che solo loro possono eseguire le richieste DELETE in segmenti crescenti. I nodi di interrogazione che si sono iscritti al canale DML filtrano prima i messaggi DELETE nei segmenti in crescita, individuano le entità facendo corrispondere le chiavi primarie fornite con i filtri bloom dei segmenti in crescita dedicati alla query e quindi registrano le operazioni di cancellazione nei segmenti corrispondenti.

I nodi di interrogazione che non possono sottoscrivere il canale DML possono elaborare solo richieste di ricerca o di interrogazione su segmenti sigillati, perché possono solo sottoscrivere il canale Delta e ricevere i messaggi DELETE inoltrati dai nodi dati. Dopo aver raccolto tutti i messaggi DELETE nei segmenti sigillati dal Delta-Channel, i nodi di interrogazione localizzano le entità facendo corrispondere le chiavi primarie fornite con i filtri bloom dei segmenti sigillati e quindi registrano le operazioni di cancellazione nei segmenti corrispondenti.

Alla fine, in una ricerca o in un'interrogazione, i nodi di interrogazione generano un set di bit basato sui record di cancellazione per omettere le entità cancellate e cercare tra le entità rimanenti di tutti i segmenti, indipendentemente dallo stato del segmento. Infine, il livello di coerenza influisce sulla visibilità dei dati cancellati. Con il livello di consistenza Strong (come mostrato nell'esempio di codice precedente), le entità cancellate sono immediatamente invisibili dopo l'eliminazione. Se invece si adotta il livello di consistenza Bounded, ci saranno diversi secondi di latenza prima che le entità cancellate diventino invisibili.

Cosa succederà in seguito?

Nella serie di blog sulle nuove funzionalità 2.0, ci proponiamo di spiegare il design delle nuove funzionalità. Leggete di più in questa serie di blog!

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

Continua a Leggere