By now we have a pile of chunks (Part 2), each turned into a vector of numbers (Part 3). This part answers the two questions that turn those vectors into a working search engine: how do we measure that two vectors are "close," and how do we find the closest ones among millions without checking every single one? The answers are cosine similarity and a clever index called HNSW — both of which are far friendlier than they sound.

A vector index (or vector database) stores all your chunk vectors and is purpose-built to answer one question fast: "given this query vector, which stored vectors are nearest?" Azure AI Search, for example, provides exactly this.

Measuring "closeness" between vectors

In Part 3 we drew chunks as dots on a meaning-map and said "find the nearest dots." But what does nearest mean for a list of 1,536 numbers? We need an actual measure of distance. There are a few, and you'll meet these names constantly:

MeasureIntuitionNotes
Cosine similarityThe angle between two vectors — are they pointing the same way?The default for text embeddings. Ignores length, focuses on direction (meaning).
Dot productDirection and magnitude combined.Fast; equivalent to cosine when vectors are normalised (most are).
Euclidean distanceStraight-line distance between the two dots.Intuitive, but for text, angle usually beats raw distance.

Why cosine, in one picture

Cosine similarity asks: do these two vectors point in the same direction? Two chunks about refunds point almost the same way (small angle → similarity near 1.0). A refund chunk and a leave chunk point in very different directions (big angle → similarity near 0). It deliberately ignores how "long" a vector is, because for meaning we care about direction, not magnitude. The score runs from 1.0 (identical meaning) down toward 0 (unrelated), and the system simply ranks chunks by it.

Cosine similarity to the query "return a faulty laptop?"
Refunds & returnschunk_01 · handbook p.12
0.91
IT equipment policychunk_18 · handbook p.20
0.78
Expense claimschunk_03 · handbook p.7
0.41
Parental leavechunk_02 · handbook p.5
0.18

The system scores every chunk, sorts by score, and keeps the top few. Here the refund and IT-equipment chunks win.

You'll often see this called k-nearest-neighbor (k-NN) search: return the k chunks nearest to the query. If k = 3, you get the three highest-scoring chunks. We'll tune k in Part 5.

The scaling problem

Scoring four chunks is trivial. But a real knowledge base might hold millions of chunks. Comparing the query against every single one — called a flat or brute-force search — gives perfect results but gets painfully slow as the collection grows. Doing a million 1,536-number comparisons for every keystroke doesn't scale.

So we make a classic engineering trade: give up a tiny bit of accuracy for an enormous speed-up. Instead of checking everything (exact search), we use approximate nearest-neighbor (ANN) search, which finds almost always the right neighbours while looking at only a small fraction of the data.

Exact (flat / brute-force)Approximate (ANN)
AccuracyPerfect — always the true nearestVery high — occasionally misses an edge case
Speed at scaleSlow; grows with collection sizeFast; barely grows with collection size
When to useSmall collections, or when 100% recall is criticalThe default for large, production knowledge bases

HNSW: how approximate search stays fast

The most popular ANN method is HNSW — Hierarchical Navigable Small World. The name is scary; the idea is delightfully simple, and there's a perfect real-world analogy: travelling across a country.

Suppose you're at a random town and want to reach a specific house. You don't inspect every house in the country. Instead you use layers of transport:

  1. Top layer — flights. Take a long flight to land in roughly the right region of the country. A few big hops cover huge distances.
  2. Middle layer — highways. Drive the motorways to get into the right city.
  3. Bottom layer — local streets. Navigate street by street to the exact house.

HNSW builds exactly this kind of multi-layer map of your vectors. The top layer has a few "long-haul" links that let a search jump across the whole space in a couple of steps; lower layers have progressively shorter, denser links for fine-grained navigation. A query starts at the top, makes a few big jumps to the right neighbourhood, then drops down layer by layer to home in on the true nearest chunks — touching only a tiny handful of vectors along the way.

HNSW — zoom in through layers, like flights → highways → streets
Top layer — long hopsA few big jumps land near the right region
Middle layer — medium hopsNavigate into the right neighbourhood
Bottom layer — short hopsStep to the exact nearest chunks (top-k)

By starting coarse and refining, HNSW finds the nearest vectors among millions in milliseconds, visiting only a sliver of the data.

You don't implement HNSW — your vector store does. But knowing it exists explains two things you'll see in tuning: parameters that trade index build time / memory against search accuracy, and why search stays fast even as your collection grows from thousands to millions of chunks.

What's actually stored in the index

A vector index entry is more than just numbers. For each chunk you typically store three things together, and all three earn their keep:

One record in the vector index
chunk_01
vectorfloat[1536] — used for similarity search
text"Faulty items may be returned within 30 days…"
metadatasource, page, date, permissions

The vector finds the match; the text is what we hand to the model; the metadata enables filtering and citations (Part 5).

Keeping the index fresh

Your documents change — policies get updated, pages get added, old ones retired. A production index needs a refresh strategy so it doesn't drift out of date:

Tools like Azure AI Search support indexers that watch a source (such as a SharePoint library or blob storage) and keep the index in sync automatically, including change detection — so you rarely rebuild from scratch.

Remember the rule from Part 3: if you ever change the embedding model, every vector in the index must be regenerated. A model change isn't an update — it's a full re-index, because old and new vectors live in different meaning-spaces.

Where we are now

We can now take a question, embed it, and retrieve the top few most-relevant chunks from millions in milliseconds. That's a complete retrieval engine. What remains is the part the user actually sees: turning those retrieved chunks into a trustworthy answer — and squeezing out the last bit of accuracy with hybrid search and reranking.

What's next

Part 5: Retrieval, Reranking & Generation closes the series. We'll choose how many chunks to fetch (top-k), combine vector search with keyword search (hybrid) and metadata filters, add a reranking pass that reorders candidates with a smarter model, then assemble the final prompt so the model answers only from the retrieved context — with citations. That's the whole pipeline, end to end.

DS

Dhaval Shah

Cloud Solution Architect — 18+ years across SharePoint, Microsoft 365, and Azure AI.