Product quantization (PQ) compresses an embedding by splitting it into subvectors and replacing each subvector with the identifier of a nearby centroid. The resulting list of centroid identifiers is the embedding’s PQ code. section 13.7.3
PQ first divides a d-dimensional vector space into M subvector spaces. It clusters the subvectors in each space, commonly with k-means, and stores centroid-to-subvector mappings in codebooks. Each document receives one centroid ID per subspace, and those IDs are concatenated into its indexed PQ code. section 13.7.3
At query time, the query embedding is divided in the same way. Distances from each query subvector to the subspace centroids are calculated and cached in a lookup table, allowing approximate distances for indexed document codes. section 13.7.3
Use PQ when vector-search scale makes memory and similarity computation costly:
- Compress the entire embedding representation more deeply than scalar or binary quantization. section 13.7.3
- Trade some recall for lower storage requirements and faster approximate search, then recover relevance by reranking candidates with more precise similarity calculations. section 13.7 section 13.7.3
Building a PQ index with FAISS
A Python implementation creates an IndexPQ with the embedding dimensionality, 16 subvectors, and 8 bits per subvector, trains it on document embeddings, adds those embeddings, and writes the index to disk. Search can then be benchmarked against a full index and evaluated again after reranking.
Measured trade-offs
Reported benchmarks show substantial index-size reductions and faster search, but recall varies: one listing reports 1.34 MB, 2.092 ms, and 0.3333 recall before reranking versus 0.6800 reranked recall; another reports 2.23 MB, 4.061 ms, and 0.5778 recall versus 0.9911 reranked recall.


