
- This demo is intended for a Jupyter notebook but works in any Python REPL.
- Key goals:
- Build a tiny deterministic embedding function (no ML).
- Store embeddings (optionally) in ChromaDB.
- Compare a linear (brute-force) search vs. a pruned (indexed) search.
- Measure and compare the number of distance computations.
| Step | Description | Example file |
|---|---|---|
| 1 | Minimal environment imports | demo_setup.py |
| 2 | Create dataset and deterministic embedder | data_and_embed.py |
| 3 | (Optional) Upsert vectors into ChromaDB | store_in_chroma.py |
| 4 | Linear (brute-force) search and measurement | linear_search.py |
| 5 | Build a toy index (3 buckets) | build_index.py |
| 6 | Indexed (pruned) search and comparison | indexed_search.py, compare_results.py |
- We use 6 short documents to keep the demo compact.
- The embedding is a 3-dimensional count vector that measures matches against three small keyword buckets: travel, policy, and service.
- This deterministic embedder makes results reproducible and easy to reason about.
- This demonstrates how to upsert a list of vectors into a Chroma collection.
- Many production vector DBs perform indexing in the background; we still build a toy index here to illustrate pruning.
- Linear scanning computes the Euclidean (L2) distance from the query embedding to every stored embedding.
- We count how many distance computations (“checks”) occur.
- Query: “flight rules”
- Top results (approx):
('airport security rules', distance 1.0),('book flight ticket', distance ~1.4142) - Distance checks: 6
Note: exact tuple formatting may vary, but distances and counts are deterministic for this embedder.
- Linear scans grow linearly with dataset size — for millions or billions of vectors this becomes infeasible.
- Indexing partitions or prunes the search space, so the system computes distances only for a small subset of candidates.
- We build a very small index by grouping documents based on argmax of their 3-d embedding.
- This produces three buckets: 0 = travel-ish, 1 = policy-ish, 2 = service-ish.
- For a query, compute its embedding, pick the target bucket with argmax, and compute distances only inside that bucket.
- The linear scan checks every vector (6 checks in this demo).
- The toy index prunes to the selected bucket; for our example it checks only the vectors in that bucket (2 checks), saving work.
- Used group: 0
- Top results (indexed):
('book flight ticket', distance ~1.4142),('hotel room reservation', distance ~1.4142) - Distance checks (indexed): 2
- Comparison:
- Linear scan checks: 6
- Indexed search checks: 2
- Saved checks: 4
Summary and takeaway
- Linear (brute-force) search computes distances against every stored vector and does not scale well.
- Indexing partitions or prunes candidate vectors so queries require far fewer distance checks.
- Even a trivial 3-bucket partition illustrates how pruning reduces checks from 6 to 2 in this example.
- Understanding indexing (and index types) is crucial when designing large-scale vector search systems.
- ChromaDB docs
- Jupyter
- FAISS (IVF, PQ) and HNSW resources linked above for deeper exploration.