IVF and Product Quantization Indexes

Engineering
Share on LinkedIn Share on X Share on Reddit Share on HN Share on Bluesky

title: "IVF and Product Quantization Indexes" slug: "vector-search-ivf-pq-index" description: "Understand IVF and product quantization for vector search: how they reduce memory, recall trade-offs, when to use them over HNSW, and tuning parameters for large-scale indexes." datePublished: "2026-03-05" dateModified: "2026-07-17" tags:



title: "vector-search-ivf-pq-index" slug: "vector-search-ivf-pq-index" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:



title: "vector-search-ivf-pq-index" slug: "vector-search-ivf-pq-index" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:



title: "vector-search-ivf-pq-index" slug: "vector-search-ivf-pq-index" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:



title: "vector-search-ivf-pq-index" slug: "vector-search-ivf-pq-index" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:



title: "vector-search-ivf-pq-index" slug: "vector-search-ivf-pq-index" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:



title: "IVF and Product Quantization Indexes" slug: "vector-search-ivf-pq-index" description: "Understand IVF and product quantization for vector search: how they reduce memory, recall trade-offs, when to use them over HNSW, and tuning parameters for large-scale indexes." datePublished: "2026-03-05" dateModified: "2026-07-17" tags:



Our FAISS index for 200 million image embeddings needed 1.2 TB of RAM with a flat HNSW index. The server had 256 GB. Switching to IVF-PQ brought memory down to 38 GB with recall@10 dropping from 99% to 91% — acceptable for a "similar images" feature where users scroll through results. IVF and product quantization are the techniques that make billion-scale vector search economically viable, and understanding their trade-offs is essential when HNSW runs out of memory.

IVF: search fewer vectors

IVF (Inverted File Index) clusters vectors into nlist groups using k-means:

Cluster 0: [v1, v7, v23, ...]
Cluster 1: [v2, v15, v41, ...]
...
Cluster nlist-1: [v3, v9, v31, ...]

At query time, find the nprobe nearest centroids and search only those clusters:

import faiss

dimension = 1536
nlist = 4096  # number of clusters

quantizer = faiss.IndexFlatL2(dimension)
index = faiss.IndexIVFFlat(quantizer, dimension, nlist)

# Training requires representative data
index.train(training_vectors)  # at least nlist vectors
index.add(all_vectors)

index.nprobe = 32  # search 32 nearest clusters
distances, indices = index.search(query_vector, k=10)

Key parameters

Parameter What it controls Tuning
nlist Number of clusters sqrt(num_vectors), e.g., 4096 for 10M
nprobe Clusters searched per query Higher = better recall, slower. Start at 16-64

nlist too low — large clusters, slow per-cluster search. nlist too high — small clusters, training needs more data, marginal gains. nprobe too low — misses vectors in adjacent clusters, poor recall. nprobe too high — approaches brute-force within searched clusters.

Product quantization: compress vectors

PQ splits each vector into m sub-vectors and quantizes each to one of ksub centroids:

1536-dim vector → 48 sub-vectors of 32 dims each
Each sub-vector → nearest of 256 centroids (1 byte index)
Total storage: 48 bytes (vs 6144 bytes for float32)
m = 48       # number of sub-vectors
nbits = 8    # bits per sub-quantizer (256 centroids)

index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)
index.train(training_vectors)
index.add(all_vectors)
index.nprobe = 32

Compression ratio: 1536 × 4 bytes / 48 bytes ≈ 128x compression.

Recall impact of PQ

PQ introduces approximation error because vectors are lossy-compressed. The impact depends on:

Typical recall@10 drop: 2-8% compared to exact search. Measure on your data.

IVF-PQ: combining both

The production combination for large-scale search:

index = faiss.IndexIVFPQ(quantizer, 1536, nlist=8192, m=48, nbits=8)
index.train(training_vectors)
index.add(all_vectors)
index.nprobe = 64

IVF reduces the number of vectors to compare. PQ reduces the cost of each comparison. Together they enable billion-vector search on a single machine.

IVF-PQ vs HNSW

Aspect HNSW IVF-PQ
Memory High (full vectors + graph) Low (compressed vectors)
Recall Excellent (95-99%) Good (85-95%)
Latency Low (5-20ms) Moderate (10-50ms)
Insert Incremental Batch-oriented
Training None Requires training pass
Scale Up to ~50M per node Billions per node

pgvector IVFFlat

pgvector supports IVFFlat (IVF without PQ):

CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

-- Tune probes at query time
SET ivfflat.probes = 20;

No product quantization in pgvector — vectors are stored at full precision. IVFFlat is pgvector's memory-conscious option, but HNSW is generally preferred when data fits in RAM.

When to use each index type

Dataset size?
├── < 1M vectors → Flat (exact search, no index needed)
├── 1M - 50M, fits in RAM → HNSW (best recall-latency)
├── 50M - 500M, memory pressure → IVF-Flat (full vectors, clustered)
└── > 500M or memory-critical → IVF-PQ (compressed, billion-scale)

Training best practices

IVF indexes need training data representative of the full dataset:

Optimized query pipeline

For maximum recall with IVF-PQ, use a two-stage approach:

  1. Coarse search — IVF-PQ retrieves top-100 candidates cheaply
  2. Rerank — compute exact distance on the 100 candidates, return top-10
distances, indices = ivfpq_index.search(query, k=100)
candidates = [all_vectors[i] for i in indices[0]]
exact_distances = np.linalg.norm(candidates - query, axis=1)
top_10 = np.argsort(exact_distances)[:10]

This recovers most of the recall lost to PQ compression with minimal extra compute.

Faiss operational patterns

If you self-host Faiss indices:

Snapshot indices to object storage after build. Rebuild pipeline should be reproducible from embedding parquet files plus factory string in git.

When PQ compression fails visually

Product thumbnails and UI screenshots encoded with aggressive PQ show visible artifacts in similarity search—"find similar looking button" returns wrong matches. For visual similarity, prefer full-precision or HNSW without PQ on smaller corpora; use PQ on text embedding indices where semantic fuzziness absorbs quantization error.

Run perceptual spot checks: query with known nearest neighbor IDs after PQ migration; if ground truth neighbors disappear from top-10, increase code size or reduce compression.

Training IVF centroids

IVF quality depends on k-means training sample — use 256× nlist vectors minimum from representative corpus. Retrain after major embedding model change; old centroids in wrong space destroy recall.

When to choose IVF-PQ over HNSW

Billion-scale corpus with relaxed recall — IVF-PQ wins on RAM. Legal or medical RAG needing high recall stays on HNSW or brute re-rank top-100 from IVF.

Practical follow-through (1)

Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.

Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.

Practical follow-through (2)

Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.

Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.

Practical follow-through (3)

Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.

Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.

Resources

Frequently asked questions

What is the main production risk with vector search ivf pq index?

Teams ship without field measurement—vector search ivf pq index failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors.

When should we prioritize vector search ivf pq index?

Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly.

How do we validate vector search ivf pq index changes?

Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR.

Hiring a senior Android / Flutter engineer?

I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.

Get in touch →