Day 115 ยท The library with a meaning-based index

Embeddings & Vector Databases

You will be able to
  • Choose an embedding model deliberately (dimensions, domain, cost, and the lock-in it creates)
  • Explain exact vs approximate nearest-neighbor search and the HNSW recall/speed trade
  • Build and query a vector index with Chroma-style code: add, upsert, metadata filters
  • Pick the right distance metric and say when cosine vs dot product vs Euclidean differ
Today's ~125 minutes
Spaced-rep: due cards + explain chunk-size trade-off aloud (D114)10 min
ELI5 + tech read; vector-search visualizer (watch HNSW hop)25 min
Guided: VecStore contract + Chroma lab40 min
Practice: find the exact-search cliff20 min
Project: build_index.py dry run20 min
Quiz + flashcards10 min

Builds on: Day 113 โ€” RAG architecture ยท Day 92 โ€” Embeddings โ€” meaning as geometry ยท Day 50 โ€” Vectors & cosine similarity

The analogy

A normal library index answers "where is the book titled X?" โ€” you must know the exact title. A meaning-based library is stranger and better: every book's CONTENT is boiled down to a point on a giant map, where books about similar things sit near each other. To find "something about taking time off work," you boil your question down to a point on the same map and grab the nearest neighbors โ€” even if no book contains your exact words. "Vacation policy" sits right next to "time off," because the map was drawn from meaning, not spelling.

The map is the embedding space (Day 92's map of meaning). The vector database is the librarian who can find nearest neighbors FAST: with a million books, checking the distance to every single one per question is too slow, so the librarian builds shortcut walkways between neighborhoods (an ANN index like HNSW) and hops along them โ€” visiting maybe a thousand books instead of a million, and almost always finding the true nearest ones.

Why this matters on the job

This is the O(nยฒ)/O(n) moment from Day 22 arriving in production: exact search over every chunk is linear per query and fine at 10k chunks, but a 20M-chunk enterprise corpus at 50 queries/sec needs ANN indexes โ€” knowing WHERE that line sits is an interview staple and a real architecture decision you'll defend to customers. Just as important is the operational side FDEs live in: embedding-model version lock-in (change the model, re-embed everything), metadata filtering for per-customer access control, and upsert lifecycles for docs that change daily.

Watch it happen

The meaning-based library โ€” ANN candidate buckets, then a careful rerank

step 1 / 6
refund policybilling faq
[0]
leave policyholidaysbenefits
[1]
api docssdk guide
[2]
sso setupsecurity
[3]

A vector index at rest: document chunks clustered into cells by MEANING โ€” billing chunks together, HR together. Comparing a query against all million chunks would work, but at answer-the-user speed it's too slow.cells = neighborhoods in embedding space (IVF / HNSW regions)

Guided practice

guided 1

A vector store from scratch โ€” the contract

20 min
  1. Create vecstore.py with the starter code: a tiny class with the EXACT api shape of a real vector DB โ€” add, upsert, query with where filters โ€” over brute-force cosine. Runs in the browser interpreter.
  2. Run it. Note the three behaviors the tests demonstrate: (a) top-k ranking; (b) a where filter restricting results to handbook docs; (c) an upsert replacing an old vector under the same ID โ€” the doc-changed lifecycle.
  3. Predict, then verify: after upserting hb-01 with new text, does the old text ever come back? Why is a STABLE id scheme what made replacement (not duplication) happen?
  4. This class IS the mental model: everything a vector DB adds beyond it is speed (HNSW), persistence, and scale.
๐Ÿ python โ€” editable, runs in your browser
Ctrl/โŒ˜+Enter runs ยท Tab indents ยท numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)
guided 2

The real thing: Chroma over your Day 114 chunks

20 min

This exercise needs a local Python environment (pip install chromadb sentence-transformers) โ€” the in-browser interpreter can't run it; if you're browser-only today, read the code line by line and map each call onto your VecStore, then run it tonight.

  1. Create chroma_lab.py with the starter code. It ingests the structure-aware chunks from Day 114's policy doc into Chroma, which embeds them automatically (all-MiniLM-L6-v2, 384 dims, runs on CPU).
  2. Run it. The killer test is the last query: "how much time off do I get" โ€” the vocabulary-mismatch query your Day 113 bag-of-words retriever FAILED. Real embeddings place "time off" near "vacation." Confirm it now retrieves the right chunk.
  3. Try the where filter โ€” then break it: filter for a source that doesn't exist and see the graceful empty result.
  4. Re-run the script. Note get_or_create_collection + stable IDs make re-ingest idempotent โ€” accidental double-ingest is the classic index-poisoning bug.
๐Ÿ python โ€” editable, runs in your browser
Ctrl/โŒ˜+Enter runs ยท Tab indents ยท numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)

On your own

Find the exact-search cliff

20 min

Using your pure-Python VecStore, measure where brute force stops being fine. Generate synthetic corpora of n = 1_000, 10_000, 100_000 random 384-dim vectors (random.random()), time 20 queries against each (reuse Day 22's timing harness), and extrapolate: at what n does a single query exceed 100 ms? Then write a 5-line recommendation: for the capstone corpus (~2k chunks), is an ANN index justified on latency grounds โ€” or is the honest answer "exact search, revisit at 100k"?

Hints: per-query cost is O(nยทd) โ€” confirm the linear ratio between the three sizes. Python loops are ~100x slower than NumPy/real DBs; note that your cliff estimate is conservative and say by how much.

Ship before you stop

Index the capstone corpus (dry run)

Build build_index.py: an ingest script that takes a folder of markdown files (create 4โ€“6 fake Nimbus docs, or reuse Day 114's), applies your structure-aware chunker with the Day 114 decision-card defaults, stamps metadata (source, section path, position, model name "bow-v0"), and loads everything into your VecStore โ€” plus a Chroma variant behind an if USE_CHROMA flag for local runs. Include a smoke test: 5 queries with expected source sections, asserting the right section appears in top-2. This script IS the seed of your capstone's ingest pipeline; on Day 119 you will point it at the real corpus.

Rubric โ€” check what you completed (0/6)

Common mistakes & misconceptions

  • Reaching for a hosted vector DB at 3k chunks. Exact search is O(nยทd), perfect-recall, and instant at that scale โ€” complexity must be earned by n, latency, or ops needs.
  • Mixing embedding model versions in one index. Vectors from different models/versions are geometrically incomparable; the symptom is quietly mediocre retrieval, not an error.
  • Forgetting ANN recall < 100%. HNSW can miss the true nearest chunk; if you never measure retrieval recall (Day 136), these misses masquerade as "the model is dumb."
  • Choosing dot product for unnormalized vectors without meaning to. Magnitude then influences ranking โ€” long chunks win regardless of relevance. For unit vectors, cosine/dot/Euclidean rank identically.
  • Random or content-hash chunk IDs. Doc updates then ADD vectors instead of replacing them, and stale chunks keep answering. Deterministic IDs + upsert = the update lifecycle.
  • Applying metadata filters as a post-filter on ANN results. You can get back fewer than k (or zero) hits; engines must filter during traversal โ€” know which yours does.
Knowledge check

Q1. You re-embed new docs with your embedding provider's v3 model into an index full of v2 vectors. What happens?

Q2. When is brute-force exact search the RIGHT engineering choice?

Q3. Your embedding model outputs unit-normalized vectors. Choosing cosine vs dot product vs Euclidean changesโ€ฆ

Go deeper โ€” curated resources

docsChroma โ€” getting started (client, collections, query) โ†—20 minarticlePinecone Learning Center โ€” HNSW & vector indexes โ†—25 mindocsSentence-Transformers โ€” pretrained embedding models โ†—15 mindocsQdrant docs โ€” filtering & payloads โ†—15 min
If you have a third hour
  • pgvector โ€” vectors inside Postgres โ€” If the customer already runs Postgres, one extension gives vectors + SQL + transactions with no new infra: a very common FDE recommendation. Compare its IVFFlat vs HNSW index options.
Done means
  • VecStore demonstrates add/upsert/query-with-filter; upsert lifecycle explained
  • Chroma lab run locally (or fully traced if browser-only) โ€” the D113 failing query now retrieves correctly
  • Exact-search cliff measured with the linear ratio confirmed
  • build_index.py committed with passing smoke test
  • Quiz โ‰ฅ 2/3
How this connects

โ† Back: Day 50's cosine similarity and Day 92's map of meaning are now infrastructure. Day 22's growth-shape reasoning told you exactly when brute force dies โ€” today you measured the cliff yourself.

Forward โ†’: Day 116 fuses this dense index with BM25 because embeddings still miss exact identifiers. Day 119 points build_index.py at the capstone corpus, and Day 149 puts the vector DB into your docker-compose stack.

Unlocks: D116 Hybrid Search ยท D117 Reranking & Query Transforms ยท D119 Week 17 Checkpoint: Capstone Kickoff โ€” Docs-QA v0 ยท D122 Agents III โ€” Memory & Context