Szczegółowy przewodnik dotyczący rozwoju Chromadb w Pythonie

Instalacja

pip install chromadb

Utrwalanie danych Chromadb

import chromadb

Możesz określić ścieżkę przechowywania pliku bazy danych Chroma. Jeśli dane istnieją, plik bazy danych zostanie automatycznie załadowany podczas uruchamiania programu.

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

Parametr path to ścieżka do pliku bazy danych Chroma.

Uwaga: Dla bazy danych Chroma, utworzenie obiektu klienta raz jest wystarczające. Wielokrotne ładowanie i zapisywanie wielu klientów w tej samej ścieżce może prowadzić do nieoczekiwanego zachowania, w tym do usunięcia danych. Ogólnie rzecz biorąc, w aplikacji powinien być utworzony tylko jeden klient Chroma.

Niektóre często używane funkcje obiektu klienta:

client.reset()  # Czyści i całkowicie resetuje bazę danych

Operacje kolekcji

Chromadb używa podstawowego elementu collection do zarządzania kolekcjami danych wektorowych, które można porównać do tabel w MYSQL.

Tworzenie, przeglądanie i usuwanie kolekcji

Chroma używa nazwy kolekcji w adresie URL, dlatego ma pewne ograniczenia dotyczące nazewnictwa:

  • Długość nazwy musi mieścić się w przedziale od 3 do 63 znaków.
  • Nazwa musi rozpoczynać się i kończyć małą literą lub liczbą, a w środku może zawierać kropki, myślniki i podkreślenia.
  • Nazwa nie może zawierać dwóch kolejnych kropek.
  • Nazwa nie może być poprawnym adresem IP.

Aby utworzyć kolekcję, musisz określić nazwę kolekcji i opcjonalną funkcję obliczania wektorów (nazywaną również funkcją osadzania). Jeśli jest dostarczona funkcja osadzania, musi być podawana za każdym razem, gdy jest dostępna kolekcja.

Uwaga: Celem funkcji obliczania wektorów (funkcji osadzania) jest obliczenie wektora tekstu.

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

Funkcja osadzania przyjmuje tekst jako wejście i zwraca obliczony wektor.

Uwaga: Początkujący mogą się uczyć z samouczków modeli osadzania tekstu.

Możesz odwołać się do istniejącej kolekcji za pomocą funkcji .get_collection, użyć .delete_collection do usunięcia kolekcji. Można również użyć .get_or_create_collection do odwołania się do kolekcji (jeśli istnieje) lub jej utworzenia, jeśli nie istnieje.

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

Inne często używane operacje na kolekcji:

collection.peek() # Zwraca listę pierwszych 10 danych w kolekcji
collection.count() # Zwraca całkowitą liczbę danych w kolekcji
collection.modify(name="new_name") # Zmienia nazwę kolekcji

Określanie metody obliczania odległości wektorów

Funkcja create_collection obejmuje również opcjonalny parametr metadanych. Ustawiając wartość hnsw:space, można dostosować metodę obliczania odległości w przestrzeni wektorowej.

Uwaga: Dane wektorowe reprezentują podobieństwo między wektorami poprzez obliczanie odległości przestrzennej między wektorami. Im bliżej odległość, tym wyższe podobieństwo, i na odwrót.

collection = client.create_collection(
        name="collection_name",
        metadata={"hnsw:space": "cosine"} # wartość domyślna to metoda obliczania l2
    )

Dopuszczalne opcje dla hnsw:space to "l2", "ip" lub "cosine". Domyślnie jest to "l2".

Dodawanie danych do kolekcji

Użyj metody .add aby dodać dane do Chroma.

Dodaj dane bez bezpośredniego określania wektorów dokumentów:

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

Jeśli Chroma otrzyma listę dokumentów, automatycznie użyje funkcji osadzania kolekcji do obliczenia wektorów dla dokumentów (jeśli funkcja osadzania nie została określona podczas tworzenia kolekcji, zostanie użyta wartość domyślna). Chroma przechowa również same dokumenty. Jeśli dokument jest zbyt duży, by obliczyć go przy użyciu wybranej funkcji osadzania, wystąpi wyjątek.

Każdy dokument musi mieć unikalne ID (ids). Dodanie tego samego ID dwukrotnie spowoduje przechowywanie tylko pierwotnej wartości. Opcjonalnie, możesz podać listę słowników metadanych (metadatas) dla każdego dokumentu, aby przechowywać dodatkowe informacje, które można wykorzystać do filtrowania danych podczas zapytań.

Alternatywnie, możesz bezpośrednio podać listę powiązanych z dokumentem danych wektora, a Chroma użyje dostarczonych przez Ciebie danych wektorowych bez automatycznego obliczania wektorów.

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=[{"rozdział": "3", "werset": "16"}, {"rozdział": "3", "werset": "5"}, {"rozdział": "29", "werset": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

Jeśli dostarczone wymiary danych wektorowych (długość) nie pasują do wymiarów kolekcji, wystąpi wyjątek.

Możesz również przechowywać dokumenty gdzie indziej i dostarczyć Chromie dane wektorowe oraz listę metadanych. Możesz użyć identyfikatorów (ids) do powiązania wektorów z dokumentami przechowywanymi gdzie indziej.

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

Uwaga: Główną funkcją bazy danych wektorów jest wyszukiwanie podobieństw semantycznych na podstawie danych wektorowych. Aby zmniejszyć rozmiar bazy danych wektorów i poprawić wydajność, możemy wybrać przechowywanie danych wektorowych i niektórych niezbędnych atrybutów filtrujących w bazie danych wektorów. Inne dane, takie jak treść artykułu, można przechowywać w bazach danych takich jak MYSQL, o ile są one powiązane poprzez ID.

Zapytywanie o dane kolekcji

Metoda .query może być używana do zapytywania zbiorów danych Chroma na wiele sposobów.

Można zapytać, używając zestawu query_embeddings (danych wektorowych).

Wskazówka: W rzeczywistych scenariuszach rozwoju, query_embeddings są zwykle uzyskiwane poprzez najpierw obliczenie wektora zapytania użytkownika za pomocą modelu osadzeń tekstowych, a następnie wykorzystanie tego wektora do zapytania o podobne treści.

collection.query(
    query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
    n_results=10,
    where={"metadata_field": "is_equal_to_this"},
    where_document={"$contains":"search_string"}
)

Zapytanie zwróci n_results wyników, które najlepiej pasują do każdego wektora zapytania (query_embedding) sekwencyjnie. Opcjonalnie można dostarczyć słownik filtru where, aby filtrować wyniki na podstawie metadanych powiązanych z każdym dokumentem. Dodatkowo, opcjonalnie można dostarczyć filtr where_document, aby filtrować wyniki na podstawie zawartości dokumentu.

Jeśli dostarczone query_embeddings nie są zgodne z wymiarami kolekcji, wystąpi wyjątek. Aby zapewnić spójne wymiary wektorów, użyj tego samego modelu osadzeń tekstu do obliczania wektorów.

Można także zapytać, używając zestawu tekstów zapytań. Chroma najpierw obliczy wektor dla każdego tekstu zapytania, używając funkcji osadzania kolekcji, a następnie wykona zapytanie, używając wygenerowanych wektorów tekstowych.

collection.query(
    query_texts=["doc10", "thus spake zarathustra", ...],
    n_results=10,
    where={"metadata_field": "is_equal_to_this"},
    where_document={"$contains":"search_string"}
)

Można także użyć .get do zapytania o dane z kolekcji po id.

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

.get również obsługuje filtry where i where_document. Jeśli nie podane jest żadne id, zostaną zwrócone wszystkie elementy w kolekcji pasujące do filtrów where i where_document.

Określanie zwracanych pól

Podczas korzystania z get lub query, można użyć parametru include do określenia zwracanych danych--embeddings, documents, lub metadatas, a dla zapytań, należy zwrócić dane odległości. Domyślnie Chroma zwraca dokumenty i metadane, oraz zwraca dane odległości dla zapytań, podczas gdy "ids" zawsze zwraca. Można określić pola do zwrócenia, przekazując tablicę nazw pól do parametru includes metody query lub get.

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

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

Korzystanie z filtrów where

Chroma obsługuje filtrowanie zapytań na podstawie metadanych i zawartości dokumentu. Filtr where służy do filtrowania metadanych, a filtr where_document służy do filtrowania zawartości dokumentu, a poniżej wyjaśniono, jak napisać wyrażenia warunkowe filtrów.

Filtrowanie według metadanych

Aby filtrować metadane, należy dostarczyć słownik filtra where dla zapytania. Słownik musi mieć następującą strukturę:

{
    "metadata_field": {
        <Operator>: <Value>
    }
}

Filtrowanie metadanych obsługuje następujące operatory:

  • $eq - równa się (string, integer, float)
  • $ne - różne od (string, integer, float)
  • $gt - większe niż (int, float)
  • $gte - większe niż lub równe (int, float)
  • $lt - mniejsze niż (integer, float)
  • $lte - mniejsze niż lub równe (int, float)

Użycie operatora $eq jest równoważne z użyciem filtra where.

{
    "metadata_field": "search_string"
}

{
    "metadata_field": {
        "$eq": "search_string"
    }
}

Filtrowanie zawartości dokumentu

Aby filtrować zawartość dokumentu, należy dostarczyć słownik filtra where_document dla zapytania. Słownik musi mieć następującą strukturę:

{
    "$contains": "search_string"
}

Korzystanie z operatorów logicznych

Możesz również użyć operatorów logicznych $and oraz $or do połączenia wielu filtrów.

Operator $and zwróci wyniki pasujące do wszystkich filtrów na liście.

{
    "$and": [
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        },
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        }
    ]
}

Operator $or zwróci wyniki pasujące do dowolnej z warunków na liście.

{
    "$or": [
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        },
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        }
    ]
}

Aktualizacja danych w kolekcji

Korzystając z .update, możesz zaktualizować dowolne właściwości danych w kolekcji.

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

Jeśli identyfikator nie zostanie znaleziony w kolekcji, zostanie zarejestrowany błąd, a aktualizacja zostanie zignorowana. Jeśli podany dokument nie ma odpowiadającego wektora, funkcja wbudowania kolekcji zostanie wykorzystana do obliczenia wektora.

Jeśli podane dane wektorowe mają inny wymiar niż kolekcja, wystąpi wyjątek.

Chroma obsługuje również operację upsert, która może zaktualizować istniejące dane i wstawić nowe dane, jeśli nie istnieją.

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

Usuwanie danych z kolekcji

Chroma obsługuje użycie .delete do usuwania danych z kolekcji przez id. Wektory, dokumenty i metadane związane z każdymi danymi zostaną również usunięte.

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

.delete obsługuje również filtr where. Jeśli nie podano identyfikatora, usunie wszystkie elementy w kolekcji pasujące do filtru where.