Vector stores are the secret sauce behind any good retrieval-augmented generation (RAG) system, and LlamaIndex gives you a unified way to talk to several of the most popular ones: Pinecone, Weaviate, and Chroma.
Let’s see how this plays out with some actual data. Imagine you’ve got a few text documents you want to index.
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext
from llama_index.vector_stores.pinecone import PineconeVectorStore
from llama_index.vector_stores.weaviate import WeaviateVectorStore
from llama_index.vector_stores.chroma import ChromaVectorStore
import weaviate
import pinecone
import chromadb
# --- Configuration (replace with your actual credentials/setup) ---
# Pinecone
pinecone.init(api_key="YOUR_PINECONE_API_KEY", environment="YOUR_PINECONE_ENV")
pinecone_index_name = "llamaindex-demo"
# Weaviate
weaviate_client = weaviate.Client("http://localhost:8080") # Or your Weaviate instance
weaviate_class_name = "LlamaIndexDemo"
# Chroma
chroma_client = chromadb.Client() # Or chromadb.PersistentClient(path="/path/to/db")
chroma_collection_name = "llamaindex-demo"
# --- Load Documents ---
# Create dummy documents if you don't have any
import os
if not os.path.exists("data"):
os.makedirs("data")
with open("data/doc1.txt", "w") as f:
f.write("This is the first document. It talks about apples and oranges.")
with open("data/doc2.txt", "w") as f:
f.write("The second document discusses bananas and grapes. They are fruits.")
with open("data/doc3.txt", "w") as f:
f.write("A third document mentioning berries and melons. All are delicious.")
documents = SimpleDirectoryReader("data").load_data()
# --- Indexing with Pinecone ---
# Ensure Pinecone index exists (or create it)
if pinecone_index_name not in pinecone.list_indexes():
pinecone.create_index(pinecone_index_name, dimension=1536) # Assuming OpenAI embeddings, dimension is 1536
pinecone_vector_store = PineconeVectorStore(
pinecone_index=pinecone.Index(pinecone_index_name),
# You might need to specify 'namespace' if you want to isolate data
)
storage_context_pinecone = StorageContext.from_defaults(vector_store=pinecone_vector_store)
index_pinecone = VectorStoreIndex.from_documents(
documents, storage_context=storage_context_pinecone
)
query_engine_pinecone = index_pinecone.as_query_engine()
print("Pinecone index created and documents added.")
# --- Indexing with Weaviate ---
# Ensure Weaviate schema exists (or create it)
class_obj = {
"class": weaviate_class_name,
"description": "A demo class for LlamaIndex",
"vectorizer": "text2vec-openai", # Or your preferred vectorizer
"moduleConfig": {
"text2vec-openai": {
"vectorIndexType": "hnsw",
"vectorizer": "text2vec-openai"
}
}
}
if not weaviate_client.schema.exists(weaviate_class_name):
weaviate_client.schema.create_class(class_obj)
weaviate_vector_store = WeaviateVectorStore(
weaviate_client=weaviate_client,
class_name=weaviate_class_name,
)
storage_context_weaviate = StorageContext.from_defaults(vector_store=weaviate_vector_store)
index_weaviate = VectorStoreIndex.from_documents(
documents, storage_context=storage_context_weaviate
)
query_engine_weaviate = index_weaviate.as_query_engine()
print("Weaviate index created and documents added.")
# --- Indexing with Chroma ---
# Ensure Chroma collection exists (or create it)
try:
chroma_collection = chroma_client.get_collection(chroma_collection_name)
except:
chroma_collection = chroma_client.create_collection(chroma_collection_name)
chroma_vector_store = ChromaVectorStore(
chroma_collection=chroma_collection,
)
storage_context_chroma = StorageContext.from_defaults(vector_store=chroma_vector_store)
index_chroma = VectorStoreIndex.from_documents(
documents, storage_context=storage_context_chroma
)
query_engine_chroma = index_chroma.as_query_engine()
print("Chroma index created and documents added.")
# --- Querying ---
print("\n--- Querying Pinecone ---")
response_pinecone = query_engine_pinecone.query("What fruits are mentioned?")
print(response_pinecone)
print("\n--- Querying Weaviate ---")
response_weaviate = query_engine_weaviate.query("Tell me about berries.")
print(response_weaviate)
print("\n--- Querying Chroma ---")
response_chroma = query_engine_chroma.query("Are apples and oranges discussed?")
print(response_chroma)
# --- Cleanup (optional) ---
# pinecone.delete_index(pinecone_index_name)
# weaviate_client.schema.delete_class(weaviate_class_name)
# chroma_client.delete_collection(chroma_collection_name)
The core idea is that LlamaIndex abstracts away the specifics of each vector store. You create a VectorStore object for Pinecone, Weaviate, or Chroma, then pass that to StorageContext.from_defaults(). VectorStoreIndex.from_documents() then handles the embedding and insertion into your chosen store. When you query, LlamaIndex again translates your natural language query into an embedding, sends it to the vector store, retrieves the most similar document chunks, and passes those to an LLM for a final answer.
Under the hood, each vector store has its own way of indexing and searching. Pinecone is a managed cloud service, optimized for massive scale and low latency. It uses technologies like Approximate Nearest Neighbor (ANN) search with algorithms like HNSW (Hierarchical Navigable Small Worlds) to quickly find similar vectors without comparing every single one. Weaviate is an open-source vector database that also supports ANN search and offers advanced features like GraphQL APIs and cross-referencing between data objects. Chroma is a newer, lightweight, and often self-hostable option, great for getting started or for applications that don’t require the scale of Pinecone or the feature set of Weaviate. It’s designed for ease of use and can run in-memory or persistently.
When you use VectorStoreIndex.from_documents(), LlamaIndex relies on an underlying TextEmbedder (like OpenAI’s text-embedding-ada-002 by default) to convert your document chunks into numerical vectors. These vectors are then sent to the VectorStore. The VectorStore stores these vectors along with the original text (or a reference to it). During a query, the query text is also embedded, and the VectorStore finds the vectors (and thus documents) that are closest in the vector space to the query vector. The distance metric used for this comparison (e.g., cosine similarity, Euclidean distance) is handled by the vector store itself, though LlamaIndex can influence this through its embedding models and store configurations.
The one thing that often trips people up is the schema definition for Weaviate. Unlike Pinecone or Chroma which are more freeform for simple text embedding, Weaviate requires you to define a "class" with properties. LlamaIndex’s WeaviateVectorStore handles mapping your document content to a text property within that class, but you need to ensure the class and its vectorizer configuration are set up correctly for Weaviate to do its job. If you don’t specify a vectorizer or use one that’s not configured in your Weaviate instance, indexing will fail silently or with obscure errors.
Once you’ve got your data indexed in one of these stores, the next step is often to combine multiple data sources or implement more sophisticated retrieval strategies.