Guida dettagliata dello sviluppo di Chromadb in Python

Installazione

pip install chromadb

Persistenza dei dati di Chromadb

import chromadb

È possibile specificare il percorso di archiviazione per il file del database di Chroma. Se i dati esistono, il file del database verrà automaticamente caricato all'avvio del programma.

client = chromadb.PersistentClient(path="/data/tizi365.db")

Il parametro path è il percorso del file del database di Chroma.

Nota: Per un database di Chroma, creare un oggetto client una volta è sufficiente. Caricare e salvare più client nello stesso percorso può portare a comportamenti inaspettati, inclusa l'eliminazione dei dati. Generalmente, dovrebbe essere creato solo un client di Chroma nell'applicazione.

Alcune funzioni comunemente utilizzate dell'oggetto client:

client.reset()  # Cancella e reimposta completamente il database

Operazioni sulla Collezione

Chromadb utilizza il primitivo collection per gestire collezioni di dati vettoriali, che possono essere paragonati a tabelle in MYSQL.

Creazione, Visualizzazione ed Eliminazione delle Collezioni

Chroma utilizza il nome della collezione nell'URL, quindi ha alcune restrizioni di denominazione:

  • La lunghezza del nome deve essere compresa tra 3 e 63 caratteri.
  • Il nome deve iniziare e terminare con una lettera minuscola o un numero e può contenere punti, trattini e trattini bassi.
  • Il nome non può contenere due punti consecutivi.
  • Il nome non può essere un indirizzo IP valido.

Per creare una collezione, è necessario specificare il nome della collezione e una funzione di calcolo vettoriale opzionale (nota anche come funzione di embedding). Se viene fornita una funzione di embedding, questa deve essere fornita ogni volta che si accede alla collezione.

Nota: Lo scopo della funzione di calcolo vettoriale (funzione di embedding) è calcolare il vettore del testo.

collection = client.create_collection(name="my_collection", embedding_function=emb_fn)
collection = client.get_collection(name="my_collection", embedding_function=emb_fn)

La funzione di embedding prende il testo in input e restituisce un vettore calcolato.

Nota: I principianti possono apprendere dai tutorial sul modello di embedding del testo.

È possibile fare riferimento a una collezione esistente con la funzione .get_collection e utilizzare .delete_collection per eliminare una collezione. È inoltre possibile utilizzare .get_or_create_collection per fare riferimento a una collezione (se esiste) o crearla se non esiste.

collection = client.get_collection(name="tizi365")
collection = client.get_or_create_collection(name="tizi365")
client.delete_collection(name="tizi365")

Altre operazioni comunemente utilizzate sulla collezione:

collection.peek() # Restituisce una lista dei primi 10 dati nella collezione
collection.count() # Restituisce il numero totale dei dati nella collezione
collection.modify(name="nuovo_nome") # Rinomina la collezione

Specifica del Metodo di Calcolo della Distanza Vettoriale

La funzione create_collection include anche un parametro metadata opzionale. Impostando il valore di hnsw:space è possibile personalizzare il metodo di calcolo della distanza nello spazio vettoriale.

Nota: I dati vettoriali rappresentano la similarità tra vettori calcolando la distanza spaziale tra i vettori. Più è vicina la distanza, maggiore è la similarità, e viceversa.

collection = client.create_collection(
        name="nome_collezione",
        metadata={"hnsw:space": "cosine"} # l2 è il metodo di calcolo predefinito
    )

Le opzioni valide per hnsw:space sono "l2", "ip" o "cosine". Il predefinito è "l2".

Aggiunta di dati a una collezione

Utilizza il metodo .add per aggiungere dati a Chroma.

Aggiungi dati direttamente senza specificare vettori di documento:

collection.add(
    documents=["lorem ipsum...", "doc2", "doc3", ...],
    metadatas=[{"capitolo": "3", "versetto": "16"}, {"capitolo": "3", "versetto": "5"}, {"capitolo": "29", "versetto": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

Se Chroma riceve una lista di documenti, utilizzerà automaticamente la funzione di embedding della collezione per calcolare i vettori per i documenti (se una funzione di embedding non è stata fornita durante la creazione della collezione, verrà utilizzato il valore predefinito). Chroma memorizzerà anche i documenti stessi. Se un documento è troppo grande per essere calcolato utilizzando la funzione di embedding selezionata, si verificherà un'eccezione.

Ogni documento deve avere un ID univoco (ids). Aggiungere lo stesso ID due volte comporterà la memorizzazione solo del valore iniziale. Opzionalmente, puoi fornire una lista di dizionari di metadati (metadatas) per ciascun documento, per memorizzare informazioni aggiuntive che possono essere utilizzate per filtrare i dati durante le query.

In alternativa, puoi fornire direttamente una lista dei dati vettoriali correlati al documento e Chroma utilizzerà i dati vettoriali che fornisci senza calcolarli automaticamente.

collection.add(
    documents=["doc1", "doc2", "doc3", ...],
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"capitolo": "3", "versetto": "16"}, {"capitolo": "3", "versetto": "5"}, {"capitolo": "29", "versetto": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

Se le dimensioni dei dati vettoriali forniti (lunghezza) non corrispondono alle dimensioni della collezione, si verificherà un'eccezione.

Puoi anche memorizzare i documenti altrove e fornire a Chroma i dati vettoriali e la lista di metadati. Puoi utilizzare gli ID per associare i vettori ai documenti memorizzati altrove.

collection.add(
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"capitolo": "3", "versetto": "16"}, {"capitolo": "3", "versetto": "5"}, {"capitolo": "29", "versetto": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

Nota: La funzione principale del database vettoriale è la ricerca di similarità semantica basata sui dati vettoriali. Per ridurre le dimensioni del database vettoriale e migliorare l'efficienza, possiamo scegliere di memorizzare i dati vettoriali e alcuni attributi di filtraggio necessari nel database vettoriale. Altri dati, come contenuti degli articoli, possono essere memorizzati in database come MYSQL, purché siano associati tramite ID.

Interrogazione dei Dati della Collezione

Il metodo .query può essere utilizzato per interrogare i set di dati di Chroma in modi multipli.

È possibile fare interrogazioni utilizzando un set di query_embeddings (dati vettoriali).

Suggerimento: Nei casi reali di sviluppo, i query_embeddings vengono solitamente ottenuti calcolando prima il vettore della query dell'utente attraverso un modello di incorporamento del testo, e poi utilizzando questo vettore per interrogare contenuti simili.

collection.query(
    query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
    n_results=10,
    where={"campo_metadati": "è_uguale_a_questo"},
    where_document={"$contains":"stringa_da_cercare"}
)

La query restituirà i risultati n_results che meglio corrispondono a ciascun vettore di query (query_embedding) in sequenza. È possibile fornire un dizionario opzionale di filtri where per filtrare i risultati in base ai metadati associati a ciascun documento. Inoltre, è possibile fornire un dizionario di filtri where_document opzionale per filtrare i risultati in base al contenuto del documento.

Se i query_embeddings forniti non sono consistenti con le dimensioni della collezione, si verificherà un'eccezione. Per garantire dimensioni vettoriali consistenti, utilizzare lo stesso modello di incorporamento del testo per calcolare i vettori.

È inoltre possibile fare interrogazioni utilizzando un set di testi di query. Chroma calcolerà prima il vettore per ciascun testo di query utilizzando la funzione di incorporamento della collezione, e quindi eseguirà la query utilizzando i vettori di testo generati.

collection.query(
    query_texts=["doc10", "così parlò Zarathustra", ...],
    n_results=10,
    where={"campo_metadati": "è_uguale_a_questo"},
    where_document={"$contains":"stringa_da_cercare"}
)

È inoltre possibile utilizzare .get per interrogare i dati della collezione per id.

collection.get(
    ids=["id1", "id2", "id3", ...],
    where={"stile": "stile1"}
)

.get supporta anche filtri where e where_document. Se non viene fornito alcun id, restituirà tutti gli elementi della collezione che corrispondono ai filtri where e where_document.

Specifica dei Campi da Restituire

Quando si utilizza get o query, è possibile utilizzare il parametro include per specificare i dati da restituire--embeddings, documents, o metadati, e per le query, è necessario restituire i dati sulla distanza. Per impostazione predefinita, Chroma restituisce documenti e metadati, e restituisce i dati sulla distanza per le query, mentre "ids" viene sempre restituito. È possibile specificare i campi da restituire passando un array di nomi dei campi al parametro include del metodo query o get.

collection.get(
    include=["documents"]
)

collection.query(
    query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
    include=["documents"]
)

Utilizzo dei Filtri Where

Chroma supporta il filtraggio delle query in base ai metadati e al contenuto del documento. Il filtro where viene utilizzato per filtrare i metadati, mentre il filtro where_document viene utilizzato per filtrare il contenuto del documento, e quanto segue spiega come scrivere le espressioni delle condizioni di filtro.

Filtraggio per Metadati

Per filtrare i metadati, è necessario fornire un dizionario di filtro where per la query. Il dizionario deve avere la seguente struttura:

{
    "campo_metadati": {
        <Operatore>: <Valore>
    }
}

Il filtraggio dei metadati supporta i seguenti operatori:

  • $eq - uguale a (stringa, intero, float)
  • $ne - diverso da (stringa, intero, float)
  • $gt - maggiore di (int, float)
  • $gte - maggiore o uguale a (int, float)
  • $lt - minore di (intero, float)
  • $lte - minore o uguale a (int, float)

L'utilizzo dell'operatore $eq è equivalente all'utilizzo del filtro where.

{
    "campo_metadati": "stringa_da_cercare"
}

{
    "campo_metadati": {
        "$eq": "stringa_da_cercare"
    }
}

Filtraggio del Contenuto del Documento

Per filtrare il contenuto del documento, è necessario fornire un dizionario di filtro where_document per la query. Il dizionario deve avere la seguente struttura:

{
    "$contains": "stringa_da_cercare"
}

Utilizzo degli operatori logici

È possibile utilizzare anche gli operatori logici $and e $or per combinare più filtri.

L'operatore $and restituirà risultati corrispondenti a tutti i filtri nella lista.

{
    "$and": [
        {
            "campo_metadati": {
                <Operatore>: <Valore>
            }
        },
        {
            "campo_metadati": {
                <Operatore>: <Valore>
            }
        }
    ]
}

L'operatore $or restituirà risultati corrispondenti a una qualsiasi delle condizioni di filtro nella lista.

{
    "$or": [
        {
            "campo_metadati": {
                <Operatore>: <Valore>
            }
        },
        {
            "campo_metadati": {
                <Operatore>: <Valore>
            }
        }
    ]
}

Aggiornamento dei dati in una raccolta

Utilizzando .update è possibile aggiornare qualsiasi proprietà dei dati in una raccolta.

raccolta.update(
    ids=["id1", "id2", "id3", ...],
    embedding=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadati=[{"capitolo": "3", "verso": "16"}, {"capitolo": "3", "verso": "5"}, {"capitolo": "29", "verso": "11"}, ...],
    documenti=["doc1", "doc2", "doc3", ...],
)

Se un'id non viene trovato nella raccolta, verrà registrato un errore e l'aggiornamento verrà ignorato. Se il documento fornito non ha un vettore corrispondente, verrà utilizzata la funzione di embedding della raccolta per calcolare il vettore.

Se i dati vettoriali forniti hanno una dimensione diversa rispetto alla raccolta, si verificherà un'eccezione.

Chroma supporta anche l'operazione di upsert, che può aggiornare i dati esistenti e inserire nuovi dati se non esistono.

raccolta.upsert(
    ids=["id1", "id2", "id3", ...],
    embedding=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadati=[{"capitolo": "3", "verso": "16"}, {"capitolo": "3", "verso": "5"}, {"capitolo": "29", "verso": "11"}, ...],
    documenti=["doc1", "doc2", "doc3", ...],
)

Eliminazione dei dati della raccolta

Chroma supporta l'utilizzo di .delete per rimuovere i dati da una raccolta per id. I vettori, i documenti e i metadati associati a ciascun dato verranno eliminati.

raccolta.delete(
    ids=["id1", "id2", "id3",...],
    where={"capitolo": "20"}
)

.delete supporta anche un filtro where. Se non viene fornito alcun id, eliminerà tutti gli elementi nella raccolta che corrispondono al filtro where.