DS DevShelfHub Projects · AI tools
Cheatsheets / Weaviate
Cheatsheet · AI frameworks

Weaviate: Collections, Hybrid Search and RAG Reference Guide

By DevShelfHub

Collections, properties, vectorizers, queries (near_text/hybrid/bm25), filters, generative modules, multi-tenancy — the v4 client surface.

99 items 8 min Hybrid Modules Multi-tenant

Start hereQuick start · 6 you’ll reach for daily

Connectweaviate.connect_to_local()
Open collectionclient.collections.get("Article")
Vector searchcol.query.near_text("...", limit=5)
Hybridcol.query.hybrid("...", alpha=0.5)
RAGcol.generate.near_text("...", grouped_task="...")
Batch insertcol.batch.dynamic() as batch

Target versions · paceVersions

Targets: weaviate ≥ 1.25 weaviate-client (py) ≥ 4.5 weaviate-client (ts) ≥ 3

The Python client v4 is a full rewrite — gRPC by default, client.collections.get(...) instead of GraphQL builders, typed return objects. The v3 client (client.query.get(...).do()) is legacy — do not start new projects there. .classes.config / .classes.query hold the typed configuration helpers. This sheet pins to Weaviate 1.25+ and the v4 client.

Install · serverSetup

bash
# Docker — single node with text2vec + generative-openai bolted on
docker run -d --name weaviate -p 8080:8080 -p 50051:50051 \
  -e ENABLE_MODULES="text2vec-openai,generative-openai,reranker-cohere" \
  -e DEFAULT_VECTORIZER_MODULE=text2vec-openai \
  -e OPENAI_APIKEY=$OPENAI_API_KEY \
  -e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
  cr.weaviate.io/semitechnologies/weaviate:1.25

# Python client v4 — sync + async, gRPC under the hood
pip install "weaviate-client>=4.5"

# JS / TS — v3 client
npm install weaviate-client

# Health check
curl http://localhost:8080/v1/.well-known/ready
# → 200 OK once nodes are up

Where things liveCommon imports

import weaviateTop-level — connect_to_* live here.
import weaviate.classes.config as wvccSchema / vectorizer / index helpers.
from weaviate.classes.config import Property, DataType, ConfigureProperty + type enums.
from weaviate.classes.query import Filter, MetadataQuery, HybridFusion, Sort, RerankQuery DSL.
from weaviate.classes.tenants import Tenant, TenantActivityStatusMulti-tenancy types.
from weaviate.classes.data import DataObject, DataReferenceObject + reference shapes for batch ops.
from weaviate.exceptions import WeaviateQueryError, UnexpectedStatusCodeErrorCommon exceptions.

Local · cloud · embeddedConnections

weaviate.connect_to_local(host="localhost", port=8080)Docker / local. Preferred default for dev.
weaviate.connect_to_weaviate_cloud(cluster_url=..., auth_credentials=Auth.api_key(...))Managed cloud.
weaviate.connect_to_custom(http_host, grpc_host, ...)Self-hosted, custom ports / TLS.
weaviate.connect_to_embedded()Spins up a server in your process. Tests + notebooks.
headers={"X-OpenAI-Api-Key": "..."}Pass module keys per-connection. Avoids server env.
client.is_ready() / client.is_live()Health checks.
client.get_meta()Server version + enabled modules.
with client: ...Context manager closes the gRPC channel cleanly.
client.close()Mandatory if not using with. Leaks hang the gRPC pool.

Properties · vectorizers · indexCollections & schema

client.collections.create(name, properties=[...], vectorizer_config=...)Create collection (was "class" in v3).
Property(name, data_type=DataType.TEXT)TEXT, INT, NUMBER, BOOL, DATE, GEO_COORDINATES, BLOB, *_ARRAY.
Configure.Vectorizer.text2vec_openai(model="text-embedding-3-small")Server-side embedding via OpenAI module.
Configure.Vectorizer.text2vec_cohere() / huggingface() / ollama() / transformers()Other text vectorizers.
Configure.Vectorizer.none()Bring your own vectors — you pass them on insert.
Configure.Generative.openai(model="gpt-4o-mini")Wire a generative module — enables col.generate.*.
Configure.NamedVectors.text2vec_openai(name="title_vec", source_properties=["title"])Multiple vectors per object — each over a different property set.
Configure.VectorIndex.hnsw(quantizer=Configure.VectorIndex.Quantizer.pq())HNSW with product / scalar / binary quantization.
Configure.VectorIndex.flat()Brute force — for small collections.
Configure.inverted_index(bm25_b=0.75, bm25_k1=1.2)BM25 tuning for keyword search.
collections.exists(name) / get(name) / delete(name) / list_all()Lifecycle + inventory.
python
import weaviate
import weaviate.classes.config as wvcc
from weaviate.classes.config import Property, DataType

client = weaviate.connect_to_local()           # or connect_to_weaviate_cloud(...)

# Idempotent create
if not client.collections.exists("Article"):
    client.collections.create(
        name="Article",
        # Vectorize with OpenAI; only the "body" property feeds the vector
        vectorizer_config=wvcc.Configure.Vectorizer.text2vec_openai(
            model="text-embedding-3-small",
        ),
        generative_config=wvcc.Configure.Generative.openai(
            model="gpt-4o-mini",
        ),
        properties=[
            Property(name="title",     data_type=DataType.TEXT),
            Property(name="body",      data_type=DataType.TEXT),
            Property(name="tags",      data_type=DataType.TEXT_ARRAY),
            Property(name="published", data_type=DataType.DATE),
            Property(name="rating",    data_type=DataType.NUMBER),
        ],
        # HNSW + quantization
        vector_index_config=wvcc.Configure.VectorIndex.hnsw(
            quantizer=wvcc.Configure.VectorIndex.Quantizer.pq(),
        ),
    )

client.close()

data.* · batchInserts & updates

col.data.insert(properties={...}, uuid=...)Single insert. Returns the object UUID.
col.data.insert_many([DataObject(properties=..., uuid=...)])Many at once — up to a few hundred objects.
with col.batch.dynamic() as b: b.add_object(properties=...)Preferred bulk ingest — auto-tunes batch size.
col.batch.fixed_size(batch_size=200)Explicit batch size when you need predictable behavior.
b.add_object(properties=..., vector=[...])BYO vector — skips the vectorizer.
col.data.update(uuid, properties={...})Patch existing object.
col.data.replace(uuid, properties={...})Overwrite all properties.
col.data.delete_by_id(uuid)Delete one.
col.data.delete_many(where=Filter.by_property("year").less_than(2020))Delete by filter.
col.data.exists(uuid)Quick existence check.

near_text · bm25 · hybrid · fetchQueries

col.query.near_text(query="...", limit=5)Semantic / vector search via vectorizer module.
col.query.near_vector(near_vector=[...], limit=5)Vector search with your own vector.
col.query.near_object(near_object=uuid)Nearest neighbors of an existing object.
col.query.bm25(query="...", query_properties=["title^2", "body"])Keyword search with field boosts.
col.query.hybrid(query="...", alpha=0.5)Vector + BM25 fusion. alpha 0 = pure BM25, 1 = pure vector.
col.query.hybrid(..., fusion_type=HybridFusion.RANKED)RRF fusion (RELATIVE_SCORE is the default).
col.query.fetch_objects(filters=..., limit=100, offset=0)Filter + paginate without similarity.
col.query.fetch_object_by_id(uuid)Random access.
return_metadata=MetadataQuery(distance=True, score=True, explain_score=True)What to attach to each match.
return_properties=["title","tags"]Limit fields returned. Trim wire bytes.
limit / offset / sort / group_byStandard query controls. Sort needs an inverted index on the field.
python
import weaviate
from weaviate.classes.query import Filter, MetadataQuery, HybridFusion

client = weaviate.connect_to_local()
col = client.collections.get("Article")

# Pure semantic (vector) search
near = col.query.near_text(
    query="how does retrieval-augmented generation work?",
    limit=5,
    filters=Filter.by_property("tags").contains_any(["rag", "embeddings"]),
    return_metadata=MetadataQuery(distance=True, score=True),
)

# BM25-only (keyword)
bm = col.query.bm25(
    query="RAG retrieval",
    query_properties=["title^2", "body"],   # boost title
    limit=5,
)

# Hybrid — server-side fusion. alpha=0 → pure BM25, 1 → pure vector
hybrid = col.query.hybrid(
    query="RAG retrieval generation",
    alpha=0.5,
    fusion_type=HybridFusion.RELATIVE_SCORE,   # or RANKED (RRF)
    limit=5,
    return_metadata=MetadataQuery(score=True, explain_score=True),
)

for o in hybrid.objects:
    print(f"{o.metadata.score:.3f}  {o.properties['title']}")

client.close()

Filter.by_property · nestedFilters

Filter.by_property("k").equal("v")Equality.
Filter.by_property("k").not_equal("v")Inequality.
Filter.by_property("n").greater_than(10) & ...less_or_equal(100)Numeric range with bitwise &.
Filter.by_property("tags").contains_any(["a","b"])Array overlap.
Filter.by_property("tags").contains_all(["a","b"])Array AND.
Filter.by_property("title").like("rag*")Wildcard pattern.
Filter.by_property("ts").greater_than(datetime(...))Date comparison.
Filter.by_id().equal(uuid)Filter by object UUID.
Filter.by_ref(link_on="hasCategory").by_property("name").equal("AI")Filter through a cross-reference.
f1 & f2 / f1 | f2 / ~f1AND, OR, NOT via operator overloading.

Retrieve + generate in one callGenerative search (RAG)

col.generate.near_text(query, single_prompt="Summarize: {body}")Run a prompt per object. {property} placeholders.
col.generate.near_text(query, grouped_task="Combine these into a summary.")One prompt over all retrieved objects.
col.generate.hybrid(query, alpha=0.5, grouped_task="...")Hybrid retrieval + RAG generate in one call.
res.objects[i].generatedPer-object output (single_prompt).
res.generatedCombined output (grouped_task).
Configure.Generative.openai(model="gpt-4o-mini")Wired at create time. Other vendors: cohere, anthropic, mistral, ollama.
rerank=Rerank(prop="body", query="...")Two-stage retrieval — rerank with a cross-encoder module.

Tenant isolationMulti-tenancy

Configure.multi_tenancy(enabled=True, auto_tenant_creation=False)Enable at create time. Can’t toggle later.
col.tenants.create(["acme", "globex"])Provision tenants.
col.tenants.get()List all tenants + activity status.
col.tenants.update([Tenant(name="acme", activity_status=TenantActivityStatus.HOT)])HOT / COLD / FROZEN — control RAM vs disk.
col.with_tenant("acme").data.insert(...)All ops are scoped via .with_tenant(...).
col.with_tenant("acme").query.near_text("...")Tenant-scoped query.
col.tenants.remove(["acme"])Delete a tenant + its data.
Multi-tenancy in Weaviate is per-tenant shards, not just a label. COLD tenants free RAM, FROZEN moves them to cloud object storage — massive savings on inactive customers.

Cross-collection linksReferences & relationships

ReferenceProperty(name="hasCategory", target_collection="Category")Define a typed link at schema create.
col.data.reference_add(from_uuid, "hasCategory", to=target_uuid)Add a cross-reference.
col.data.reference_replace / reference_deleteManage links.
return_references=[QueryReference(link_on="hasCategory", return_properties=["name"])]Pull linked data in one query.
Filter.by_ref(link_on="hasCategory").by_property("name").equal("AI")Filter on a reference target’s property.

Schema · ingest · RAGEnd-to-end · Hybrid RAG

Idempotent create + batch insert + hybrid retrieve + RAG generate — all server-side, one call at the end.

python
# Minimal Weaviate RAG — schema, ingest, hybrid retrieve, RAG generate
import os, weaviate
import weaviate.classes.config as wvcc
from weaviate.classes.config import Property, DataType
from weaviate.classes.query import Filter

client = weaviate.connect_to_local(
    headers={"X-OpenAI-Api-Key": os.environ["OPENAI_API_KEY"]},
)

NAME = "Article"
if not client.collections.exists(NAME):
    client.collections.create(
        name=NAME,
        vectorizer_config=wvcc.Configure.Vectorizer.text2vec_openai(),
        generative_config=wvcc.Configure.Generative.openai(model="gpt-4o-mini"),
        properties=[
            Property(name="title", data_type=DataType.TEXT),
            Property(name="body",  data_type=DataType.TEXT),
            Property(name="tags",  data_type=DataType.TEXT_ARRAY),
        ],
    )

col = client.collections.get(NAME)

# Batch insert — Weaviate calls the vectorizer for you
with col.batch.dynamic() as batch:
    for d in [
        {"title": "What is RAG?", "body": "Retrieval-augmented generation joins...",
         "tags": ["rag", "intro"]},
        {"title": "Hybrid search", "body": "BM25 + vectors fuse for...",
         "tags": ["rag", "hybrid"]},
    ]:
        batch.add_object(properties=d)

# Hybrid retrieve + RAG generate in one call
res = col.generate.hybrid(
    query="explain RAG",
    alpha=0.5, limit=3,
    filters=Filter.by_property("tags").contains_any(["rag"]),
    grouped_task="Answer the question using only the retrieved articles.",
)
print(res.generated)
client.close()

Best practiceGood to know

Always close the client. v4 uses gRPC under the hood. A forgotten client.close() leaks the channel and hangs interpreter shutdown. The with weaviate.connect_to_* form is the safe default.
Use a vectorizer module for write-time embedding. Letting Weaviate call OpenAI / Cohere on insert avoids embedding drift, hides API keys from clients, and unlocks col.query.near_text("...") (otherwise you must pass a vector yourself).
Multi-tenancy with HOT / COLD beats per-tenant collections. A collection per tenant blows past the planner’s soft limits (~1000s). Tenants share schema, can be cooled to free RAM, and offer cleaner per-tenant deletes.

Common trapsWatch out for

v3 GraphQL-style code does not work on v4 clients. client.query.get(...).with_near_text(...).do() is the legacy path. v4 calls go through client.collections.get(...).query.near_text(...) and return typed objects.
Forgetting to enable multi_tenancy at create time is a one-way door. You can’t turn it on later without recreating the collection. Decide up-front whether each customer / project is a tenant.
BM25 needs an inverted index on the queried properties. Properties default to indexed, but if you flipped tokenization=Tokenization.FIELD or skipped indexing for a property, bm25 / hybrid will silently return zero hits on it.

Go deeperSee also

Weaviate FAQ

What is Weaviate used for?

Weaviate is an open-source vector database used for semantic search, retrieval-augmented generation (RAG), recommendation, and classification. It stores objects with their vector embeddings and supports near_text, hybrid (vector + BM25), and generative queries that pipe results directly into an LLM.

What is the difference between near_text and hybrid search in Weaviate?

near_text performs pure vector similarity search — the query is vectorized and compared to stored vectors. hybrid combines vector similarity with BM25 keyword matching, controlled by an alpha parameter (0 = pure BM25, 1 = pure vector). Hybrid search usually beats pure vector search for factual or name-heavy queries.

What vectorizers does Weaviate support?

Weaviate supports text2vec-openai, text2vec-cohere, text2vec-transformers (self-hosted), text2vec-ollama (local), multi2vec-clip (image and text), multi2vec-palm, and ref2vec-centroid. Set the vectorizer at collection creation time; switching later requires re-importing all objects.

What is RAG in Weaviate?

Weaviate's generative modules (generative-openai, generative-cohere, generative-anthropic) pipe retrieval results directly into an LLM. Call col.generate.near_text(query, grouped_task='summarize') and Weaviate returns both the raw objects and the LLM-generated answer in a single API call.

Is Weaviate free to use?

Yes. Weaviate is open source under the BSD 3-Clause license. You can self-host it with Docker or Kubernetes at no cost. Weaviate Cloud (WCD) offers a free sandbox tier. The Python and TypeScript clients are also open source under BSD.