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

Pinecone Cheatsheet: Indexes, Filters, Namespaces and Hybrid Search

By DevShelfHub

Serverless indexes, namespaces, upsert, filters, sparse-dense hybrid, integrated inference — the managed vector DB as a one-page reference.

92 items 7 min Serverless Hybrid Namespaces

Start hereQuick start · 6 you’ll reach for daily

Init clientpc = Pinecone(api_key=...)
Serverless indexpc.create_index(name, dim, metric, spec)
Open indexidx = pc.Index("kb")
Upsertidx.upsert(vectors=[...], namespace="ns")
Queryidx.query(vector, top_k=5, filter={...})
Statsidx.describe_index_stats()

Target versions · paceVersions

Targets: pinecone ≥ 5 @pinecone-database/pinecone ≥ 4 API 2025-04

The package renamed from pinecone-clientpinecone in v5. The old global pinecone.init(...) + environment per index is gone — everything goes through the Pinecone instance. Serverless is the default; pod-based is legacy + on its way out. Hybrid search needs metric="dotproduct" and sparse vectors. This sheet pins to v5+.

Install · authSetup

bash
# Python — v5+ client (post-rename from "pinecone-client")
pip install "pinecone>=5"

# Optional integrations
pip install pinecone[grpc]                  # high-throughput gRPC transport
pip install pinecone-text                   # sparse encoders for hybrid

# JS / TS
npm install @pinecone-database/pinecone

# API key — grab from the Pinecone console
export PINECONE_API_KEY=pcsk_...

# Smoke test
python -c "from pinecone import Pinecone; \
  print(Pinecone(api_key='$PINECONE_API_KEY').list_indexes().names())"

Where things liveCommon imports

from pinecone import PineconeEntry point — one instance per app.
from pinecone import ServerlessSpec, PodSpecIndex hosting specs.
from pinecone.grpc import PineconeGRPC as PineconegRPC transport — ~2–5× throughput for big upserts.
from pinecone import Vector, SparseValuesTyped vector dicts (optional — raw dicts also accepted).
from pinecone_text.sparse import BM25Encoder, SpladeEncoderSparse encoders for hybrid search.
from pinecone import PineconeExceptionCatch-all client exception.

Serverless · pod · lifecycleIndexes

Pinecone(api_key=...)Construct once. Reads PINECONE_API_KEY if omitted.
pc.list_indexes().names()All index names in the project.
pc.describe_index("kb")Spec + status + host URL.
pc.create_index(name, dimension, metric, spec=ServerlessSpec(...))Create serverless. Preferred for new projects.
ServerlessSpec(cloud="aws"|"gcp"|"azure", region=...)Serverless host.
PodSpec(environment, pod_type="p1.x1"|"s1.x1", pods=N)Legacy pod-based deploy.
metric="cosine" | "dotproduct" | "euclidean"Distance. dotproduct required for hybrid.
dimension=1536Must match your embedder. Cannot be changed later.
deletion_protection="enabled"Block delete_index until disabled.
pc.configure_index("kb", deletion_protection="disabled")Toggle settings without recreating.
pc.delete_index("kb")Destructive.
idx = pc.Index("kb") / pc.Index(host="https://...")Open a handle. host avoids one lookup round-trip.
python
from pinecone import Pinecone, ServerlessSpec, PodSpec

pc = Pinecone(api_key=os.environ["PINECONE_API_KEY"])

# Serverless — pay-per-use, autoscales, default for new projects
pc.create_index(
    name="kb",
    dimension=1536,                         # match your embedder
    metric="cosine",                        # cosine | dotproduct | euclidean
    spec=ServerlessSpec(cloud="aws", region="us-east-1"),
    deletion_protection="enabled",          # block accidental drops
)

# Pod-based — fixed capacity, predictable latency (legacy / large workloads)
pc.create_index(
    name="kb-pod",
    dimension=1536, metric="cosine",
    spec=PodSpec(environment="us-west1-gcp", pod_type="p1.x1", pods=1),
)

# Wait until it's ready (status="Ready", host populated)
while not pc.describe_index("kb").status["ready"]:
    time.sleep(1)

# Connect to the index
idx = pc.Index("kb")
idx.describe_index_stats()
# → {'dimension': 1536, 'index_fullness': 0.0,
#    'total_vector_count': 0, 'namespaces': {}}

upsert · update · delete · fetchUpsert & DML

idx.upsert(vectors=[(id, values, metadata), ...])Tuple form. Quickest for plain dense vectors.
idx.upsert(vectors=[{"id","values","metadata","sparse_values"}])Dict form. Required for hybrid / sparse.
idx.upsert(..., namespace="prod")Logical partition within an index.
idx.upsert(..., async_req=True)Fire-and-forget — returns a future.
idx.update(id="d1", set_metadata={"reviewed": True})Patch metadata without re-uploading the vector.
idx.update(id="d1", values=[...])Replace the vector for one id.
idx.fetch(ids=["d1","d2"], namespace="prod")Random access by id.
idx.delete(ids=["d1"], namespace="prod")Delete by id.
idx.delete(filter={"src": "stale"}, namespace="prod")Delete by metadata filter (serverless).
idx.delete(delete_all=True, namespace="prod")Wipe a namespace.
Batch ≤ 100 vectors or 2 MB / callHard caps. Chunk before upload.

k-NN · filtered · by idQuerying

idx.query(vector=[...], top_k=5)Plain k-NN.
idx.query(id="d1", top_k=5)k-NN around an existing vector.
include_values=True, include_metadata=TrueReturn vectors / metadata alongside scores.
filter={"k": "v"}Metadata pre-filter — runs before ANN.
namespace="prod"Scope the search. Omit = default namespace.
vector=dense, sparse_vector={"indices","values"}Hybrid query. Needs dotproduct index.
res["matches"][i]["score"]Distance / similarity for each match.
idx.list_paginated(prefix="user-42-", limit=100)Enumerate ids (serverless only).

$eq · $in · $and · ...Metadata filters

{"k": "v"}Equality shorthand.
{"k": {"$eq": v}} / {"$ne": v}Equality / inequality.
{"k": {"$gt": n, "$lte": m}}Numeric range.
{"k": {"$in": [...]}} / {"$nin": [...]}Set membership.
{"tags": {"$exists": true}}Field present.
{"$and": [c1, c2]} / {"$or": [c1, c2]}Boolean composition. Mix freely.
Allowed metadata typesstr, number, bool, list of strings. No nested objects.
~40 KB per vector metadataSoft cap. Bigger payloads belong in a separate store keyed by id.

Multi-tenant isolationNamespaces

idx.upsert(..., namespace="tenant-a")Logical partition. No cost to create — created on first write.
idx.query(..., namespace="tenant-a")Search scoped to one namespace.
idx.describe_index_stats()Per-namespace vector counts.
idx.delete(delete_all=True, namespace="tenant-a")Drop one tenant’s data cleanly.
Namespaces are scopes inside one index, not separate indexes. Quotas, dimension, and metric are shared. Use them for per-tenant isolation, A/B experiments, or staging data.

Dense + sparseHybrid search

metric="dotproduct" at index creationRequired. Cosine + euclidean don’t support sparse.
BM25Encoder().fit(corpus)Train sparse statistics on your corpus.
bm25.encode_documents(text)Encode for upsert — returns {"indices", "values"}.
bm25.encode_queries(text)Encode for query — same shape.
SpladeEncoder()Learned sparse model. Heavier but strong for technical text.
alpha · reweight dense and sparseMultiply dense by α, sparse by (1−α) before query. Tune on a holdout.
python
# Hybrid = dense semantic + sparse lexical (BM25-ish) in one query.
# Requires a dotproduct index (cosine breaks the math).
from pinecone import Pinecone
from pinecone_text.sparse import BM25Encoder

pc = Pinecone(api_key=os.environ["PINECONE_API_KEY"])
idx = pc.Index("kb-hybrid")        # created with metric="dotproduct"

# 1. Fit BM25 once on your corpus, then save its IDF table
bm25 = BM25Encoder()
bm25.fit(["text of doc 1", "text of doc 2", "..."])

# 2. Upsert dense + sparse for every chunk
docs = [{"id": "d1", "text": "..."}, {"id": "d2", "text": "..."}]
idx.upsert(vectors=[{
    "id": d["id"],
    "values": dense_embedder(d["text"]),                 # dense vector
    "sparse_values": bm25.encode_documents(d["text"]),   # {"indices", "values"}
    "metadata": {"text": d["text"]}
} for d in docs])

# 3. Query — alpha trades off dense (1.0) ↔ sparse (0.0)
def weight(dense, sparse, alpha=0.5):
    return ([v * alpha for v in dense],
            {"indices": sparse["indices"],
             "values":  [v * (1 - alpha) for v in sparse["values"]]})

dv = dense_embedder("what is RAG?")
sv = bm25.encode_queries("what is RAG?")
hd, hs = weight(dv, sv, alpha=0.5)
idx.query(vector=hd, sparse_vector=hs, top_k=5, include_metadata=True)

Hosted embed · rerankPinecone Inference

pc.inference.embed(model, inputs, parameters)Hosted embeddings — multilingual-e5-large, llama-text-embed-v2, etc.
parameters={"input_type": "query" | "passage"}Most embedders split query vs passage encoding.
pc.inference.rerank(model, query, documents, top_n)Hosted cross-encoder rerank — bge-reranker-v2-m3, cohere-rerank-3.5.
integrated index with embed=...Index that embeds text on the server — you upsert strings, not vectors.
idx.upsert_records(records=[{"id","text","..." }], namespace=...)Integrated-inference upsert path.
idx.search(query={"inputs": {"text": "..."}, "top_k": 5})Integrated-inference query path.

LangChain · LlamaIndex · HaystackFramework integrations

from langchain_pinecone import PineconeVectorStoreModern LangChain wrapper. Preferred.
PineconeVectorStore.from_documents(docs, embedding, index_name="kb")Build store from LangChain Documents.
store.as_retriever(search_kwargs={"k": 4, "namespace": "prod"})Drop into an LCEL chain.
from langchain.vectorstores import PineconeLegacy import path — superseded.
from llama_index.vector_stores.pinecone import PineconeVectorStoreLlamaIndex adapter.
from haystack_integrations.document_stores.pinecone import PineconeDocumentStoreHaystack 2 document store.

Create · upsert · queryEnd-to-end · Minimal RAG store

Serverless index + OpenAI embeddings + filtered query, namespaced. Drop in your own loader and you have a working store.

python
# Minimal Pinecone RAG store — create, upsert, filter, query
import os, time
from pinecone import Pinecone, ServerlessSpec
from openai import OpenAI

pc  = Pinecone(api_key=os.environ["PINECONE_API_KEY"])
oai = OpenAI()

NAME, DIM = "kb", 1536
if NAME not in [i.name for i in pc.list_indexes()]:
    pc.create_index(
        name=NAME, dimension=DIM, metric="cosine",
        spec=ServerlessSpec(cloud="aws", region="us-east-1"),
    )
    while not pc.describe_index(NAME).status["ready"]:
        time.sleep(1)

idx = pc.Index(NAME)

def embed(texts):
    return [d.embedding for d in
            oai.embeddings.create(model="text-embedding-3-small", input=texts).data]

docs = [
    ("d1", "Pinecone is a managed vector DB.",          {"src": "blog"}),
    ("d2", "RAG joins retrieval with generation.",      {"src": "docs"}),
    ("d3", "Namespaces isolate data per tenant.",       {"src": "docs"}),
]
vecs = embed([t for _, t, _ in docs])
idx.upsert(vectors=[(i, v, {**m, "text": t})
                    for (i, t, m), v in zip(docs, vecs)],
           namespace="prod")

q   = embed(["what is RAG?"])[0]
res = idx.query(vector=q, top_k=2, namespace="prod",
                filter={"src": {"$eq": "docs"}}, include_metadata=True)
for m in res["matches"]:
    print(f"{m['score']:.3f}  [{m['metadata']['src']}]  {m['metadata']['text']}")

Best practiceGood to know

Pick namespaces, not separate indexes, for tenant isolation. Namespaces are free, share quota, and isolate at query time. New indexes are billable, slow to spin up, and won’t share describe_index_stats().
Use the gRPC client for big upserts. from pinecone.grpc import PineconeGRPC drops you on a binary transport with multiplexed streams — usually 2–5× faster for bulk ingest.
Pre-filter selectivity matters. Pinecone applies metadata filters before ANN. A highly selective filter (1% of vectors) with top_k=5 can leave the ANN walker no candidates — bump top_k or pre-shard via namespaces.

Common trapsWatch out for

Hybrid only works on dotproduct indexes. Setting metric="cosine" and then passing sparse_vector= gives an error or silently bad rankings — pick the metric before you start ingesting.
pinecone.init(...) is gone. Any guide that calls pinecone.init(api_key=, environment=) is pre-v3. Use Pinecone(api_key=) and a Spec at index creation.
Upsert has a 2 MB / 100-vector cap per request. Exceeding it errors mid-batch. Chunk in code; the SDK does not paginate for you. For very large loads, parallelize with the async client.

Go deeperSee also

Pinecone FAQ

What is Pinecone?

Pinecone is a managed serverless vector database designed for similarity search at scale. It stores embedding vectors alongside metadata, supports fast approximate nearest-neighbor queries, and handles infrastructure scaling automatically. Pinecone is commonly used as the retrieval layer in RAG pipelines alongside embedding models from OpenAI, Cohere, or sentence-transformers.

What is a serverless index in Pinecone?

A serverless index stores vectors in an object-storage-backed layer and scales to zero when idle, so you pay only for queries and storage rather than uptime. Create one with pc.create_index(name, dimension, spec=ServerlessSpec(cloud, region)). Serverless indexes are recommended for most new workloads; pod-based indexes remain available for high-throughput production use cases.

How do metadata filters work in Pinecone?

Metadata filters let you scope a query to a subset of vectors that match key-value conditions. Pass a filter dict to the query call, for example filter={'genre': {'$eq': 'sci-fi'}}. Pinecone evaluates the filter before computing similarity, so filtered queries can be significantly faster than post-filtering on the client. Index metadata fields you plan to filter on for best performance.

What is hybrid search in Pinecone?

Hybrid search combines dense vector similarity (semantic) with sparse BM25-style keyword matching in a single query. Pass both a dense values vector and a sparse values dict, plus an alpha weight (0=pure sparse, 1=pure dense) to control the blend. Hybrid search improves recall for queries where exact keyword matches matter alongside semantic similarity, such as product or document retrieval.

How does integrated inference work in Pinecone?

Pinecone's integrated inference lets you upsert plain text and run queries without managing embeddings yourself. Configure an index with a model name (e.g. multilingual-e5-large) and Pinecone embeds the text on your behalf at upsert and query time. This removes the need to call a separate embedding API, simplifying the pipeline and reducing latency for most RAG applications.