Introducing Chroma Database

Introducing Chroma Database

Understanding vectors paves the way for comprehending vector databases. There’s a wide variety available, and LangChain seamlessly integrates with many. You can explore the full list of supported vector databases at https://python.langchain.com/v0.1/docs/integrations/vectorstores/.

Vector databases specialize in storing data within vector spaces and excel at handling unstructured queries. This means they can take your raw, unprocessed questions, convert them into embeddings, and then use those embeddings to retrieve relevant data from their storage.

Thanks to LangChain, the interface for working with different vector databases is remarkably consistent. In this section, you’ll focus on Chroma, but remember that you can readily substitute it with another supported database if you prefer.

Getting Started With Chroma

Chroma is an open-source vector database designed with developer productivity in mind. Chroma is available in Python and JavaScript as of this writing. In your notebook, you can install it with:

pip install chromadb

Just as with most databases, it comes with a client module that allows you to access a Chroma database instance. However, you don’t always have to access the client directly to work with Chroma. For instance, when you work with LangChain’s Chroma component, it’ll give you access to Chroma via its own set of APIs. In the code below, you’ll see how to access the client using the native chromadb module you just installed:

import chromadb

chroma_client = chromadb.Client()

But with LangChain, you can access Chroma with:

from langchain_chroma import Chroma

db = Chroma(
  embedding_function=embeddings_model,
)

The client instance would certainly give you plenty of low-level access to Chroma, potentially offering more control than LangChain’s wrapper. But rest assured, LangChain’s wrapper also exposes many of the APIs you’ll generally need to work with Chroma effectively.

By default, Chroma stores data in memory. However, this means your data will be lost when the app restarts, defeating the purpose of persistent storage. You’ll configure Chroma to store your data on disk. With this change, Chroma will load your saved documents whenever it starts:

client = chromadb.PersistentClient(path="/path/to/storage/directory")

Chroma uses terminologies similar to NoSQL databases, meaning that in Chroma your SQL tables are called collections and your records are documents. Using the snippet below, create a collection and add some documents to the collection:

collection = chroma_client.create_collection(name="olympics_collection")

collection.add(
    documents=[
        "The 2024 Olympics had the most gender-balanced field of play in 
          history, with equal numbers of male and female athletes.",
        "The United States won the most medals, with 40 gold and 126 total 
          medals. China came in second with 40 gold medals and 91 total medals.",
        "France spent around $10 billion to host the games, which was more than
          three times less than the cost of the 2020 Tokyo Olympics."
    ],
    ids=["id-1", "id-2", "id-3"]
)

The actual data goes into the documents argument, while their respective unique identifiers go into the ids argument. In a production app, you can use a UUID function instead to guarantee some high levels of non-ID collision throughout your collection.

By executing the code above, you’ve inserted records into your table in SQL terms. To retrieve your data from the collection, use the query function. It provides a query_texts argument for receiving a slice (collection) of queries, and an n_results optional parameter that specifies how many documents to return.

Remember that Chroma is a vector database, which is vastly different from SQL and NoSQL. This means your queries don’t have to follow any particular syntax. Your collection isn’t even structured. Your queries are therefore going to be written in normal English. Interesting, isn’t it? See for yourself how to do this:

results = collection.query(
  query_texts=["Which country won the most medals?"],
  n_results=2
)
print(results)

When you run it, you get:

{
  "ids": [
    [
        "id-2",
        "id-1"
    ]
  ],
  "distances": [
    [
      0.5161427855491638,
      1.2563385963439941
    ]
  ],
  "metadatas": [
    [
        None,
        None
    ]
  ],
  "embeddings": None,
  "documents": [
    [
      "The United States won the most medals, with 40 gold and 126 total medals. 
        China came in second with 40 gold medals and 91 total medals.",
      "The 2024 Olympics had the most gender-balanced field of play in history, 
        with equal numbers of male and female athletes."
    ]
  ],
  "uris": None,
  "data": None,
  "included": [
    "metadatas",
    "documents",
    "distances"
  ]
}

You can already see how powerful vector storage is in action. Your unstructured text query has returned a result that matches the stored documents. This is true for every vector store out there. Note that when you added documents to the collection earlier, Chroma embedded them. The same process happens with your queries. They are converted into embeddings, and then Chroma searches for the closest matching embeddings within its stored data.

These are the basics of the Chroma vector store. Next you’ll see a demo of how to use this with LangChain and OpenAI.

See forum comments
Download course materials from Github
Previous: Vector Embeddings Demo Next: Chroma Demo