Why must a Pinecone index use the dotproduct metric for hybrid sparse-dense search?
answer
- metric is decided once, at creation
- only one of the three metrics is allowed
- the blend has to add up linearly
- normalising would erase your weighting
- dotproduct, and it is immutable
basics
~20 sPinecone accepts sparse values only in indexes created with metric="dotproduct". Dot product is linear, so scaling the dense and sparse query vectors weights their contributions predictably; cosine and euclidean indexes reject sparse vectors, and the metric cannot be changed later.
solid answer
~50 sIn Pinecone the similarity metric is fixed when you call `create_index`, and sparse-dense records are only supported on `metric="dotproduct"`. There are two reasons. First it is a hard product constraint: upserting `sparse_values` into a cosine or euclidean index is rejected, and since the metric is immutable, discovering this later means creating a new index and re-upserting everything. Second, dot product is the only one of the three that makes the blend well-defined: the score is linear in the query vector, so multiplying the dense query by alpha and the sparse query by (1 - alpha) produces a final score of alpha·(dense dot) + (1 - alpha)·(sparse dot). Cosine would normalise those scale factors straight back out, making the weighting a no-op, and euclidean distance is smaller-is-better, which does not add meaningfully to a similarity score.
code
python · 22 linesfrom pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="YOUR_KEY")
pc.create_index(
name="docs-hybrid",
dimension=768,
metric="dotproduct", # required for sparse-dense records
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)
index = pc.Index("docs-hybrid")
index.upsert(
vectors=[
{
"id": "doc-1",
"values": [0.01] * 768,
"sparse_values": {"indices": [10, 4021, 55130], "values": [0.6, 0.3, 0.9]},
"metadata": {"source": "handbook"},
}
]
)go deeper
Remember the one hard rule: hybrid records need an index created with metric="dotproduct", and the metric is set once at index creation.
Be ready to explain the mechanics — the metric is immutable, sparse values are rejected on cosine indexes, and dot product is linear so scaling the query vectors is what produces the weighted blend.
Expect to walk through the migration from an existing cosine index: new index, full re-upsert, normalisation check, verification against labelled queries, then cutover. Name the silent failure where the query path never sends the sparse half.
Own the upstream decision: committing to dotproduct at index-creation time constrains every future retrieval option, so decide whether hybrid is in scope before the first corpus load and budget the rebuild cost if it is not.
## What a hybrid record looks like in Pinecone Pinecone does hybrid search by letting a single record carry two vectors at once: the usual dense embedding in `values`, and a sparse vector in `sparse_values`, given as `{"indices": [...], "values": [...]}`. The sparse side is a bag of term weights — each index is an integer id for a token in some vocabulary, each value is that token's weight. At query time you pass both `vector=` and `sparse_vector=` to `index.query(...)`, and Pinecone returns one ranked list with one `score` per match, computed over both parts together. ## The metric is chosen at creation and is immutable `create_index` takes `dimension`, `metric` and a `spec` (for example `ServerlessSpec(cloud=..., region=...)`). The metric may be `cosine`, `dotproduct` or `euclidean`. Sparse-dense records are supported **only** on `dotproduct`. Trying to upsert a record with `sparse_values` into a cosine index fails, and there is no ALTER-style operation to change a metric afterwards: the fix is to create a fresh index with `metric="dotproduct"` and re-upsert the whole corpus. That is why this shows up in interviews — it is a design decision you must make before you write a single vector, and getting it wrong is a full rebuild. ## Why dot product is the mathematically necessary choice A dot product is linear in the query: score(q, d) = q · d, so score(alpha·q, d) = alpha · (q · d). That linearity is the whole trick. If you scale the dense query by alpha and the sparse query by (1 - alpha) before sending them, Pinecone's internal score becomes alpha · (dense_q · dense_d) + (1 - alpha) · (sparse_q · sparse_d) which is exactly a convex blend of a semantic score and a lexical score — produced by the engine, in one query, with no client-side merging of two result lists. Pinecone exposes no server-side `alpha` parameter; this scaling is how the weighting is expressed. ## Why cosine and euclidean cannot do this Cosine similarity divides by the norms of both vectors. Any positive scalar multiple of the query gives an identical cosine score, so multiplying the query by alpha would change nothing — the weighting knob would silently do nothing at all. Euclidean is a distance: lower is better, the opposite polarity from a similarity, and over a very high-dimensional mostly-zero sparse vector the distance is dominated by the dimensions both vectors leave at zero, which carries almost no signal. Neither combines sensibly with a dense similarity into one orderable number. ## What choosing dotproduct costs you Dot product is unnormalised, so a vector with a larger magnitude scores higher regardless of direction. Most sentence-embedding models emit vectors of roughly unit norm, and if yours does, dot product and cosine produce the *same ranking* — you lose nothing. If your model does not, L2-normalise the dense vectors yourself before upserting and before querying; otherwise long or high-energy documents will float to the top for reasons that have nothing to do with relevance. This is the single most common surprise for teams migrating an existing cosine index over to hybrid. ## Failure modes to name in an interview - **Built the index on cosine first.** Discovered at hybrid-integration time; requires a new index and a full re-upsert, plus a cutover plan. - **Forgot the sparse vector on the query.** A record can carry sparse values while the query passes only `vector=`; the query then scores purely on the dense side and nobody gets an error. Hybrid quietly degrades to semantic-only. - **Un-normalised dense vectors.** Ranking drifts toward high-magnitude documents once you leave cosine. - **Assuming the metric is per-query.** It is per-index, set once, immutable. ## Related index shape Pinecone also supports sparse-only indexes, created with `vector_type="sparse"`, and those likewise use `dotproduct` — the lexical score is a dot product of term weights either way. With that shape you run a dense query and a sparse query separately and merge the two result lists yourself, rather than getting one blended score from one index. Knowing both shapes exist, and that dot product is the common thread, is a good signal of having actually built this.
- If your embeddings are already L2-normalised, does moving from cosine to dotproduct change your results at all?No — for unit-norm vectors cosine similarity and dot product differ only by a constant denominator of 1, so the ranking is identical and the absolute scores match too. That is why the migration is usually safe. The risk appears only when the model emits vectors of varying magnitude, in which case dot product starts rewarding magnitude and you should normalise before upsert and before query.
- You already have a live cosine index and now need hybrid. What is the migration?There is no in-place change: the metric is fixed at creation. Create a second index with metric="dotproduct", re-upsert every record with both `values` and `sparse_values`, verify recall against a labelled query set, then cut reads over and delete the old index. Because the dense vectors are unchanged you do not need to re-embed — only re-upsert, plus generate the sparse side.
- What happens if a query passes only a dense vector against a hybrid index?It succeeds and returns dense-only results. Pinecone does not require the sparse half at query time, so omitting `sparse_vector=` silently turns the query back into pure semantic search with no warning. That is a classic bug when hybrid is added behind a feature flag: the records are hybrid, the query path is not, and lexical recall never materialises.
saying these in an interview costs you the question
- Thinks sparse values can be added to a cosine index
- Believes an index's metric can be changed after creation
- Says euclidean also works because sparse is just another vector
- Assumes Pinecone picks the metric automatically for hybrid
- Forgets dot product rewards magnitude on un-normalised vectors