Concepts / Vector Indexing in FAISS

Vector Indexing in FAISS

In HNSW, the index is a graph of vectors and similarity links rather than a set of buckets. Finding neighbors means moving through that graph, not looking up a hash result.

  • Programming

Why Searching Every Vector Gets Expensive

Similarity search asks a simple question: given a query vector, which stored vectors are closest to it? Many systems that work with embeddings need to answer this question again and again, often over very large collections. The answer has to be fast as well as useful, and that pressure is what makes vector indexing necessary.

The techniques covered in this article are ways of organizing stored vectors so that a search does not have to examine everything. Each one takes a different route around the cost of comparison. Before looking at those routes, it helps to understand the baseline they are trying to beat.

The Brute-Force Baseline

The obvious way to answer a similarity query is to measure the distance from the query to every stored vector and keep the best matches. This approach is accurate, because no candidate is skipped. Its weakness is cost: as the number of stored vectors grows, the number of comparisons grows with it, and the search becomes slow.

Each of the three techniques attacks that cost in a different place. Some decide which vectors are worth comparing at all. Some decide how the search moves through the stored data. Others decide how expensive each individual comparison is. Keeping these three questions separate will make the rest of the article easier to follow.

  • Locality-sensitive hashing: decides which vectors get compared, by grouping likely neighbors together before any comparison happens
  • HNSW: decides how the search moves, by following edges in a graph that links similar vectors
  • Product quantization: decides how costly each comparison is, by shrinking each vector into a compact form

Locality-Sensitive Hashing: Grouping Before Comparing

Locality-sensitive hashing, usually written LSH, is an algorithm for similarity search that works with more than just vectors. Its central move is to hash similar vectors into the same buckets. A bucket is simply a group of stored items that share one hash result. Because similar vectors land in the same bucket, the index already holds a rough grouping of likely neighbors before any query arrives.

When a query arrives, the search does not need to look at every vector in the collection. It hashes the query, finds the bucket or buckets the query lands in, and examines only the vectors stored there. The diagram below shows a small collection of nine stored vectors spread across three buckets. The query lands in Bucket A, so only the three vectors in that bucket are candidates.

Query vectorhashed on arrivalBucket Av1, v4, v9Bucket Bv2, v5Bucket Cv3, v6, v7, v8hash lands here
Which buckets does the query need to check once it has been hashed, and which stored vectors become candidates for comparison?

The diagram is illustrative, with invented vector names and bucket contents, but the mechanism is the one the source describes: the query is compared only against the bucket it lands in, not against the full collection of nine.

What do you think happens?

The query has been hashed into Bucket A. Must the search also compare the query against the vectors in Bucket B and Bucket C?

  • Yes, every bucket must be checked

  • No, only the bucket or buckets the query lands in need to be checked

Reveal answer
Answer:

No, only the bucket or buckets the query lands in need to be checked.

The source explains that the search only needs to look at the bucket or buckets the query lands in, because the likely neighbors were placed there. That is what reduces the number of comparisons.

Routing a Query to One Bucket

Worked example

Counting comparisons with and without buckets

A collection holds nine stored vectors, grouped into three buckets as shown in the diagram: Bucket A holds three vectors, Bucket B holds two, and Bucket C holds four. A query is hashed and lands in Bucket A. How many comparisons does LSH perform, compared with exhaustive search?

  1. 1
    Hash the query

    The query is hashed, and the hash result places it in Bucket A.

  2. 2
    Select the candidates

    The search looks only at the vectors stored in Bucket A: v1, v4, and v9. The other six vectors are not compared.

  3. 3
    Count the comparisons

    LSH performs three comparisons. Exhaustive search would perform nine, one for each stored vector.

  4. 4
    Name the risk

    If a true nearest neighbor happened to be hashed into Bucket B or Bucket C, the search would miss it. This is the accuracy cost of the speed gain.

Result

LSH compares 3 vectors instead of 9. The saving is real, but the answer is only as good as the bucket placement.

HNSW: Following Edges Through a Graph

HNSW, which stands for Hierarchical Navigable Small World, takes a different approach from LSH. Instead of grouping vectors into buckets, it constructs a multi-layer graph in which each node represents a vector and each edge connects two similar vectors. The graph is built ahead of time, and the search runs over it.

A nearest-neighbor search in HNSW works by traversing graph edges. The search moves from vector to vector along links that connect similar items, so each step takes it to a nearby node. The diagram shows the multi-layer structure as levels, with the search descending from a top layer toward the bottom layer, where the vectors are linked by edges.

Top layerMiddle layerBottom layerVector Anode in the graphVector Bsimilar neighbordescenddescendedge between similar vectors
How does a search move from the top layer down through the layers, and along which edges does it hop between similar vectors?

The layers are what make the structure hierarchical. The source pack describes the graph and the edge traversal, but it does not give a full layer-by-layer procedure, so this article limits its claims to those two ideas: vectors are nodes, edges link similar vectors, and the search moves along edges.

Key point

In HNSW, the index is a graph of vectors and similarity links rather than a set of buckets. Finding neighbors means moving through that graph, not looking up a hash result.

Product Quantization: Compressing Vectors into Subvectors

Product quantization, often abbreviated PQ, works on the vectors themselves. It reduces each vector into a much simpler, lower-dimensional representation by decomposing it into multiple subvectors, which are smaller pieces of the original vector. The full vector is split into parts, and the parts are used to build a compact form.

Full vectorall dimensions togetherLower-dimensionalrepresentationused to compute distancesSubvector 1first pieceSubvector 2second pieceSubvector 3third piecesplitsplitsplitreduced form
How does a full vector become a sequence of subvectors, and how do those pieces lead to a compact representation used for distances?

The diagram shows one vector split into three illustrative subvectors, feeding into a lower-dimensional representation. The point of the decomposition is what happens next: distances are computed using these lower-dimensional representations rather than the full vectors. The source notes that these representations are much faster to work with.

This is why product quantization is about the cost of each comparison. The number of stored vectors may stay the same, but every distance calculation touches a smaller, more compact form. The source pack does not quantify any accuracy loss from this step, so it should not be assumed to be zero or any particular value.

Side by Side: Core Ideas and Trade-offs

The three techniques answer the same question from different angles. LSH controls which vectors get compared by hashing them into buckets. HNSW controls how the search moves by following edges in a graph. Product quantization controls how much work each comparison costs by shrinking the vectors that are compared.

Candidate selectionHashing into bucketsSearch movementTraversing graph edgesComparison costLower-dimensional vectors
Which part of the search problem does each technique change: the candidates, the movement, or the cost of each comparison?
TechniqueCore ideaWhat it controlsTrade-offWhere implemented in FAISS
Locality-sensitive hashingHash similar vectors into the same bucketsWhich vectors get comparedSpeed gained at some cost to accuracyNot named in the source pack
HNSWMulti-layer graph in which edges link similar vectorsHow the search moves through the stored dataThe source pack does not state an accuracy cost for HNSWNot named in the source pack
Product quantizationSplit each vector into subvectors and reduce it to a lower-dimensional representationHow expensive each comparison isDistances are cheaper to compute; the source pack does not quantify accuracy lossNot named in the source pack

Comparison of the three techniques, using only what the source pack states

Mistakes Learners Make with Approximate Search

  • Common mistake

    Assuming LSH still compares the query against every stored vector

    What it looks like

    Believing that a query hashed into Bucket A is also checked against the vectors in Bucket B and Bucket C.

    Why it fails

    The search only needs to look at the bucket or buckets the query lands in.

    Do this instead

    Count only the vectors in the buckets the query lands in as candidates.

  • Common mistake

    Assuming LSH never misses a true nearest neighbor

    What it looks like

    A true nearest neighbor is hashed into Bucket C while the query lands in Bucket A.

    Why it fails

    LSH trades some accuracy for speed, so a neighbor placed in a different bucket is skipped.

    Do this instead

    Treat LSH results as the best candidates found in the buckets searched, not a guaranteed full ranking.

  • Common mistake

    Treating HNSW as a bucket lookup

    Why it fails

    HNSW does not group vectors into buckets. It builds a graph, and the search moves along edges between similar vectors.

    Do this instead

    Think of HNSW search as walking through linked nodes.

  • Common mistake

    Believing product quantization compares the original full vectors

    Why it fails

    PQ computes distances using the lower-dimensional representations built from subvectors.

    Do this instead

    Distinguish the stored compact representation from the original vector when reasoning about comparison cost.

Matching Techniques to Problems

EASY

A system has a very large collection of vectors. Searches are slow mainly because too many candidates are compared, and the team accepts that some true neighbors might be missed. Which technique targets this problem directly, and what does it trade away to gain speed?

Hints
  • Ask which of the three techniques controls which vectors get compared.
  • Recall the phrase from the source: speeds up similarity search at the cost of some accuracy.
  • The answer is the technique that groups likely neighbors together before any comparison happens.

Key Takeaways

  • Exhaustive similarity search is accurate but its cost grows with the number of stored vectors, which motivates three different routes around that cost.
  • Locality-sensitive hashing places similar vectors into shared buckets so a query only checks the buckets it lands in, trading some accuracy for speed.
  • HNSW organizes vectors as nodes in a multi-layer graph, and nearest-neighbor search moves by traversing edges between similar vectors.
  • Product quantization splits each vector into subvectors and computes distances on lower-dimensional representations, making each comparison cheaper.
  • The three techniques control different parts of the problem: which candidates are compared, how the search navigates, and how expensive each comparison is.

More concepts starting with V