Skip to main content
Weaviate is an open-source vector database with native support for BM25 hybrid search, generative AI integration, and enterprise-grade multi-tenancy. It combines semantic search with traditional keyword matching without requiring external sparse encoders.

Key features

  • Native BM25: Built-in keyword search without sparse embeddings
  • Generative search: RAG with OpenAI, Cohere, or custom LLMs
  • Multi-tenancy: Per-tenant shards for data isolation
  • Hybrid search: Vector + BM25 with configurable alpha balancing
  • GraphQL interface: Advanced querying capabilities
  • Cloud + self-hosted: Flexible deployment options

Installation

Install the Weaviate Python client:
pip install weaviate-client

Connection

Weaviate Cloud

from vectordb.databases.weaviate import WeaviateVectorDB

db = WeaviateVectorDB(
    cluster_url="https://my-cluster.weaviate.cloud",
    api_key="weaviate-api-key",
    headers={"X-OpenAI-Api-Key": "sk-..."}
)

Self-hosted instance

db = WeaviateVectorDB(
    cluster_url="http://localhost:8080",
    api_key="",  # Empty for local
    tracing_project_name="my-project"
)

Collection creation

Basic collection

db.create_collection(
    collection_name="Articles",
    properties=[
        Property(name="title", data_type=DataType.TEXT),
        Property(name="content", data_type=DataType.TEXT),
        Property(name="category", data_type=DataType.TEXT)
    ]
)

With vectorizer

Use Weaviate’s built-in vectorization:
from weaviate.classes.config import Configure

db.create_collection(
    collection_name="Articles",
    vectorizer_config=Configure.Vectorizer.text2vec_openai(),
    generative_config=Configure.Generative.openai()
)

With multi-tenancy

db.create_collection(
    collection_name="Documents",
    enable_multi_tenancy=True
)

# Create tenants
db.create_tenants(["tenant_a", "tenant_b", "tenant_c"])

Upserting documents

Standard upsert

data = [
    {
        "text": "Weaviate supports hybrid search",
        "category": "database",
        "priority": 1,
        "vector": [0.1, 0.2, ...]  # Optional custom embedding
    },
    {
        "text": "BM25 provides keyword matching",
        "category": "search",
        "priority": 2
    }
]

db.upsert(data)

Tenant-scoped upsert

db.with_tenant("tenant_a").upsert(documents)
Weaviate auto-generates UUIDs if not provided. Use "id" or "uuid" keys to specify custom IDs.

Querying

response = db.query(
    vector=[0.1, 0.2, ...],
    limit=10,
    include_vectors=True,
    return_documents=True  # Returns Haystack Documents
)

# Access results
for doc in response:
    print(f"Score: {doc.score}, Content: {doc.content}")
Uses Weaviate’s vectorizer to embed the query:
response = db.query(
    query_string="machine learning algorithms",
    limit=10,
    return_documents=True
)

Hybrid search (vector + BM25)

results = db.hybrid_search(
    query="neural networks deep learning",
    vector=embedding,  # Optional pre-computed vector
    top_k=10,
    alpha=0.5  # 1.0 = vector only, 0.0 = BM25 only
)
The alpha parameter controls the balance:
  • 1.0: Pure vector search (semantic)
  • 0.5: Balanced hybrid (default)
  • 0.0: Pure BM25 (keyword)

Metadata filtering

Weaviate uses MongoDB-style filter syntax:
# Simple equality
results = db.query(
    vector=embedding,
    filters={"category": "technology"},
    limit=10
)

# Range queries
results = db.query(
    vector=embedding,
    filters={"priority": {"$gte": 5}},
    limit=10
)

# Combined filters
results = db.query(
    vector=embedding,
    filters={
        "category": "tech",
        "published": {"$gt": "2024-01-01"}
    },
    limit=10
)

# Logical OR
results = db.query(
    vector=embedding,
    filters={
        "$or": [
            {"category": "tech"},
            {"category": "science"}
        ]
    }
)

Supported filter operators

  • $eq: Equal to
  • $ne: Not equal to
  • $gt: Greater than
  • $gte: Greater than or equal
  • $lt: Less than
  • $lte: Less than or equal
  • $in: Value in list
  • $like: Wildcard pattern matching
  • $and: Logical AND (implicit for multiple conditions)
  • $or: Logical OR

Reranking

Improve result precision with cross-encoder reranking:
results = db.query(
    query_string="artificial intelligence",
    limit=50,
    rerank={
        "prop": "content",
        "query": "What are the latest AI trends?"
    }
)

Generative search (RAG)

Single prompt per result

Generate content for each retrieved document:
response = db.generate(
    query_string="machine learning frameworks",
    single_prompt="Summarize this in one sentence: {content}",
    limit=5
)

for item in response.objects:
    print(item.generated)  # LLM-generated summary

Grouped task

Generate content from all results combined:
response = db.generate(
    query_string="neural networks",
    grouped_task="Write a comprehensive summary of these documents",
    limit=10
)

print(response.generated)  # Single combined answer

Multi-tenancy

Create and manage tenants

# Create collection with multi-tenancy
db.create_collection("SharedDocs", enable_multi_tenancy=True)

# Add tenants
db.create_tenants(["company_a", "company_b", "company_c"])

# Check tenant existence
if db.tenant_exists("company_a"):
    print("Tenant exists")

# Delete tenants
db.delete_tenants(["company_old"])

Tenant-scoped operations

# Switch to tenant context
tenant_db = db.with_tenant("company_a")

# All operations now scoped to this tenant
tenant_db.upsert(documents)
results = tenant_db.query(vector=embedding)

# Chain operations
db.with_tenant("company_b").upsert(other_docs)

Converting results

Manual conversion

Convert raw Weaviate responses to Haystack Documents:
# Query without auto-conversion
response = db.query(
    vector=embedding,
    limit=10,
    return_documents=False  # Get raw response
)

# Convert manually
documents = db.query_to_documents(
    response,
    include_vectors=True
)

for doc in documents:
    print(doc.id, doc.score, doc.embedding)

Best practices

Weaviate’s native multi-tenancy uses per-tenant shards for true isolation:
  • Good: 100s to 1000s of tenants per collection
  • Good: Enterprise SaaS with strict data isolation requirements
  • Avoid: Millions of micro-tenants (consider Milvus partition keys)
Weaviate’s BM25 is built-in, unlike other databases:
# No sparse embeddings needed!
results = db.hybrid_search(
    query="specific technical term",
    alpha=0.3  # Emphasize BM25
)
Configure generative models per collection:
from weaviate.classes.config import Configure

db.create_collection(
    "Articles",
    generative_config=Configure.Generative.openai(
        model="gpt-4"
    )
)
Requires API key in headers:
db = WeaviateVectorDB(
    cluster_url="...",
    api_key="...",
    headers={"X-OpenAI-Api-Key": "sk-..."}
)

Error handling

try:
    db.create_collection("Articles")
    db.upsert(documents)
except ValueError as e:
    print(f"Configuration error: {e}")
except Exception as e:
    print(f"Weaviate error: {e}")
finally:
    db.close()  # Clean shutdown

Closing connections

db.close()  # Releases network resources

Source reference

Implementation: src/vectordb/databases/weaviate.py Key classes and methods:
  • WeaviateVectorDB.__init__(): src/vectordb/databases/weaviate.py:74
  • create_collection(): src/vectordb/databases/weaviate.py:159
  • upsert(): src/vectordb/databases/weaviate.py:207
  • query(): src/vectordb/databases/weaviate.py:362
  • hybrid_search(): src/vectordb/databases/weaviate.py:537
  • generate(): src/vectordb/databases/weaviate.py:578
  • create_tenants(): src/vectordb/databases/weaviate.py:629

Build docs developers (and LLMs) love