UMAP vs Semantic Search

Two destinations for the same primitive. UMAP uses nearest neighbors to build a skeleton of local structure for dimensionality reduction. Semantic search uses them to retrieve answers at query time.

Part 5 of Approximate Nearest Neighbors

Two Destinations from the Same Foundation

The last four articles built up a single primitive. Given a query vector and a large collection of database vectors, find the ones that are closest. The algorithms got clever (partition, compress, design for hardware), but the question never changed.

This article is about what people do with that primitive once it works. Two destinations sit downstream of nearest-neighbor search, and they optimize for very different things. One wants structure to look at. The other wants answers to return.

Figure 1. Both methods start from the same pile of high-dimensional vectors and rely on the same nearest-neighbor primitive. UMAP uses it to build a graph, then flattens the graph into a 2D layout. Semantic search uses it to answer a steady stream of user queries with a ranked list of candidates.

Both methods need "what is near this vector?" to be fast enough and good enough. What they demand beyond that is where the two disciplines diverge. Thinking about them side by side is the clearest way to see that the three-idea stack is not one recipe but a set of dials tuned for the job at hand.

UMAP: Neighbors as Skeleton

UMAP is an algorithm for projecting high-dimensional data down to two or three dimensions so that a person can look at it. Its first step, before any layout work, is to build a k-nearest-neighbor graph over the input vectors. Each point connects to its k closest neighbors in the original space.

That graph is UMAP's model of the data. It encodes the local topology of the manifold: who is near whom. The rest of the algorithm is an optimizer that embeds the graph into 2D while trying to preserve those connections. If two points are graph-neighbors in high dimensions, the optimizer pulls them together in the plane. If they are not, it pushes them apart.

The crucial observation for our purposes: the graph does not have to be perfect. UMAP does not need the true nearest neighbors. It needs a graph that roughly captures local structure. A few mistakes are smoothed out by the optimization. This is why UMAP implementations are built on approximate nearest-neighbor libraries, not exact search.

Figure 2. A UMAP-style projection of a synthetic dataset with five latent clusters, rendered at different values of k. At k = 2, the graph is too local and the projection fragments into strings and pairs. Around k = 15 the clusters are well-separated and the layout looks how you would want it to. Past k = 100, the graph connects almost everything to almost everything, and the optimizer smears distinct clusters together. The slider blends between a handful of pre-computed layouts to show the effect.

UMAP's Priorities

Think about the cost profile. Building the k-NN graph over a million points is a one-time job. It might take minutes. The layout step that follows is also one-time, also offline. Once the projection is produced, UMAP is done. There is no "query" in the sense that semantic search has one. You do not run UMAP in response to a user action.

This reshapes every decision about the index. Build-time cost dominates, so a memory-heavy structure like HNSW that takes a while to build but has great recall for graph construction is perfectly fine. Query-time cost is irrelevant because there are no online queries. Reranking, the step where you refine approximate matches using exact distances, is pointless: the output is a layout, not a candidate list. The graph's statistical shape is the answer.

Recall of 90% for the k-NN graph is usually indistinguishable from 100% in the final layout. The optimizer pulls the picture back toward the manifold's true shape either way.

Semantic Search: Neighbors as Retrieval

Semantic search is the opposite side of the same primitive. A user types a sentence. An embedding model turns it into a vector. The index answers "which documents are closest?" and the top few are handed back to an application, usually as context for a language model or as direct results for the person doing the searching.

Every keystroke can trigger a query. Every user triggers many queries. The index is built once, often from millions or billions of documents, then hit constantly for the rest of its life.

Semantic Search's Priorities

Query latency dominates. A semantic search backend needs to answer in something like 50ms at the 99th percentile, and it needs to do that while the disk is busy and the network is noisy and other queries are running. The index is allowed to be expensive to build because you amortize that cost across the billions of queries it will serve.

This flips the set of reasonable choices. IVF-PQ with on-disk partitions, the combination that sits at the heart of systems like lancedb, is a sweet spot: cheap enough to keep hot shards in RAM, compressed enough to fit the long tail on SSD, fast enough to return the top-k in a few milliseconds. Reranking matters here; approximate codes get you the candidates, exact distances decide the final order. Recall@10 of 95% is typically "good enough" because a language model downstream can filter out the miss and the user rarely notices.

Same Primitives, Different Dials

The three ideas from this series, partition, compress, and hardware, appear in both systems. What differs is how hard each dial is turned, and why.

UMAP
Semantic Search
Idea 1
Partition
Used mainly at build time to accelerate graph construction. The partition can be coarse; small mistakes are absorbed by the layout optimizer.
Used at every query to avoid scanning the whole index. Has to balance recall against latency on every request. The partition is the main dial for the speed/accuracy tradeoff.
Idea 2
Compress
Less important. The vectors are thrown away after the graph is built. Compression is useful only if raw vectors do not fit in RAM during construction.
Aggressive. Product quantization takes a 1536-dim float vector and turns it into a few dozen bytes. Without this, billion-scale indices do not fit on any single machine's memory.
Idea 3
Hardware
CPU-parallel build. Many cores, lots of RAM, big batch jobs. Once built, the graph is a small in-memory object. Disk layout is not a concern.
Disk layout matters hugely. Hot shards in RAM, long tail on SSD, codes aligned for SIMD. GPUs pay off when many queries arrive at once. Every byte fetched from SSD counts.
Figure 4. The same three ideas under different constraints. UMAP is an offline, throughput-oriented, correctness-tolerant job. Semantic search is an online, latency-bound, high-recall service. The dials land in different places.

Build-time and Query-time Budgets

The two disciplines spend their compute budget in opposite shapes. UMAP pours almost everything into a single up-front build; nothing happens afterward. Semantic search builds once and then pays a small cost on every user interaction, forever.

Figure 5. The two workloads drawn to the same total-work budget. For UMAP, most of the cost is the one-shot k-NN graph build, plus a smaller layout pass. For semantic search, the index build is comparable in size, but it is followed by millions of tiny per-query slices. Over a realistic month of operation the query work dominates, even though each query is small.

Closing Reflection

Approximate nearest-neighbor search is infrastructure. You rarely talk to it directly, the way you rarely talk to a database query planner or a network stack. It sits below the products we actually use: the search bar that understands what you meant, the recommender that knows what you will want next, the 2D projection that makes a million-row dataset legible in a single glance.

The fact that this works at all comes down to the three ideas in this series, stacked and tuned for the job. Partition the space so you are not looking everywhere. Compress the vectors so comparisons are cheap and the data fits. Design for the hardware you are running on. Each idea is simple in isolation. Together, they make it possible to visualize a million embeddings, retrieve from a billion documents, and power a recommender over tens of billions of users, with the same primitive.

Figure 6. The full stack in one picture. The three ideas feed both destinations. The work of this series was to understand why each idea is necessary. The work of your next project is to decide how hard to turn each dial.

Thanks for reading. If you want to go deeper, the series index has all five parts in one place.