Ogni raccolta di dati è divisa in segmenti. Ciascun segmento ha uno storage vettoriale indipendente, uno storage dei payload e un indice.
I dati nei segmenti di solito non si sovrappongono. Tuttavia, memorizzare lo stesso punto in diversi segmenti non causa problemi poiché la ricerca contiene un meccanismo di deduplica.
I segmenti includono uno storage vettoriale, uno storage dei payload, un indice vettoriale, un indice dei payload e un mappatore di ID per memorizzare la relazione tra ID interni ed esterni.
I segmenti possono essere "aggiungibili" o "non aggiungibili" a seconda del tipo di storage e indice utilizzati. È possibile aggiungere, eliminare e interrogare liberamente i dati nei segmenti "aggiungibili", mentre i segmenti "non aggiungibili" possono solo leggere ed eliminare dati.
La configurazione dei segmenti in una raccolta può essere diversa e indipendente l'una dall'altra, ma è richiesto almeno un segmento "aggiungibile".
Storage Vettoriale
A seconda delle esigenze dell'applicazione, Qdrant può utilizzare una delle seguenti opzioni di storage dati. La scelta deve bilanciare la velocità di ricerca e l'uso della RAM.
Memory Storage - Memorizza tutti i vettori nella RAM, garantendo la massima velocità poiché l'accesso al disco è richiesto solo durante la persistenza.
Memmap Storage - Crea uno spazio degli indirizzi virtuale associato a un file su disco. I file mappati non vengono direttamente caricati nella RAM, ma accessibili tramite la cache delle pagine. Questo approccio consente un uso flessibile della memoria disponibile. Con abbastanza RAM, la sua velocità è quasi pari a quella dello storage in memoria.
Configurazione del Memmap Storage
Ci sono due modi per configurare l'uso di memmap (noto anche come storage su disco):
- Impostare l'opzione
on_disk
per i vettori nell'API di creazione della raccolta:
Applicabile solo a v1.2.0 e versioni successive
PUT /collections/{nome_raccolta}
{
"vettori": {
"dimensione": 768,
"distanza": "Coseno",
"on_disk": true
}
}
Questo creerà una raccolta che memorizza immediatamente tutti i vettori nello storage memmap. Questo è l'approccio consigliato quando l'istanza di Qdrant utilizza dischi veloci e deve gestire grandi raccolte.
- Impostare l'opzione
memmap_threshold_kb
. Questa opzione imposta la soglia per convertire i segmenti in memorizzazione memmap.
Ci sono due modi per implementare ciò:
- Impostare globalmente la soglia nel file di configurazione. Il nome del parametro è
memmap_threshold_kb
. - Impostare la soglia individualmente per ciascuna raccolta durante la creazione o l'aggiornamento.
PUT /collections/{nome_raccolta}
{
"vettori": {
"dimensione": 768,
"distanza": "Coseno"
},
"configurazione_ottimizzatori": {
"memmap_threshold": 20000
}
}
Il criterio di base per impostare il parametro della soglia memmap è semplice:
- Se lo scenario di utilizzo è bilanciato - impostare la soglia memmap allo stesso valore di
indexing_threshold
(impostazione predefinita: 20000). In questo caso, l'ottimizzatore non eseguirà esecuzioni aggiuntive e ottimizzerà tutte le soglie in una volta. - Se il carico di scrittura è elevato e la RAM è limitata - impostare la soglia memmap inferiore rispetto a
indexing_threshold
, ad esempio 10000. In questo caso, l'ottimizzatore convertirà prima i segmenti in memorizzazione memmap e quindi applicherà l'indicizzazione.
Inoltre, è possibile utilizzare lo storage memmap non solo per i vettori ma anche per gli indici HNSW. Per abilitare questa funzionalità, impostare il parametro hnsw_config.on_disk
su true
durante la creazione della raccolta.
PUT /collections/{nome_raccolta}
{
"vettori": {
"dimensione": 768,
"distanza": "Coseno"
},
"configurazione_ottimizzatori": {
"memmap_threshold": 20000
},
"hnsw_config": {
"on_disk": true
}
}
Archiviazione del payload
Qdrant supporta due tipi di archiviazione del payload: InMemory e OnDisk.
L'archiviazione del payload InMemory organizza i dati del payload nello stesso modo dei vettori in memoria. I dati del payload vengono caricati in memoria all'avvio del servizio, mentre il disco e RocksDB vengono utilizzati solo per la persistenza. Questo tipo di archiviazione è molto veloce ma potrebbe richiedere una grande quantità di spazio in memoria per memorizzare tutti i dati, specialmente se il payload include valori di grandi dimensioni (come riassunti di testo o addirittura immagini).
Per valori di payload di grandi dimensioni, è preferibile utilizzare l'archiviazione del payload OnDisk. Questo tipo di archiviazione legge e scrive direttamente il payload su RocksDB, evitando così la necessità di una grande quantità di memoria per lo storage. Tuttavia, l'inconveniente è la latenza di accesso. Se è necessario interrogare i vettori in base alle condizioni del payload, controllare i valori archiviati su disco potrebbe richiedere troppo tempo. In questo caso, consigliamo di creare un indice del payload per ciascun campo utilizzato per le condizioni di filtraggio per evitare l'accesso al disco. Una volta creato l'indice del campo, Qdrant manterrà sempre in memoria tutti i valori del campo indicizzato, indipendentemente dal tipo di archiviazione del payload.
È possibile specificare il tipo di archiviazione del payload desiderato tramite il file di configurazione o utilizzando il parametro della collezione on_disk_payload
durante la creazione di una collezione.
Controllo della versione
Per garantire l'integrità dei dati, Qdrant esegue tutte le modifiche dei dati in due fasi. Prima, i dati vengono scritti nel Write-ahead-log (WAL), che ordina e assegna numeri sequenziali a tutte le operazioni.
Una volta che le modifiche sono aggiunte al WAL, non vengono perse nemmeno in caso di black-out. Successivamente, le modifiche entrano nel segmento. Ciascun segmento memorizza la versione più recente delle modifiche applicate ad esso, nonché la versione di ciascun punto individuale. Se il numero sequenziale di una nuova modifica è inferiore alla versione attuale di un punto, l'aggiornatore ignorerà tale modifica. Questo meccanismo consente a Qdrant di recuperare efficientemente lo storage dal WAL in caso di arresti anomali.