Project: a minimal vector retriever

Project goal

Run vector_search.py to implement dot product, L2 norm, unit normalization, cosine, Euclidean distance, exact top-k, and Recall@k using only the Python standard library. test_vector_search.py fixes the mathematical relationships, ranking direction, invalid inputs, and command-line behavior with nine tests. The vectors are hand-constructed three-dimensional teaching data, not a real embedding model.

Environment and execution

The project has no third-party dependency. To establish a stable habit, it is still recommended to use a separate venv on Windows 11 / PowerShell 7 and place it outside the vault:

$exampleDir = (Resolve-Path '.\Knowledge\AI Agent Engineer\docs-EN\vector-fundamentals\examples').Path
$venv = Join-Path $env:LOCALAPPDATA 'Gao-venvs\vector-search'
$python = Join-Path $venv 'Scripts\python.exe'
 
py -3.11 -m venv $venv
& $python -m pip --version
& $python -B -W error (Join-Path $exampleDir 'vector_search.py')
& $python -B -O -W error (Join-Path $exampleDir 'vector_search.py')
& $python -B -W error -m unittest discover -s $exampleDir -p 'test_*.py' -v
& $python -B -O -W error -m unittest discover -s $exampleDir -p 'test_*.py' -v

No package installation is needed. pip --version only confirms that any future dependency would enter the intended environment. -B prevents bytecode caches, and -O removes ordinary assert statements. The script uses explicit exceptions for its important teaching checks, so normal and optimized modes retain the same acceptance behavior.

Data, output, and interpretation

The query is (1, 1, 0); the three document vectors represent a Python API, HTTP retries, and cat care. Under both cosine and Euclidean metrics, the script places the first two API documents in the top two:

MetricRank 1Rank 2Ranking direction
cosinepython-api, approximately 0.9986http-retry, approximately 0.9948Larger is more similar
Euclideanpython-api, approximately 0.1000http-retry, approximately 0.2449Smaller is more similar

The hand-authored relevance set is {python-api, http-retry}, so Recall@2=2/2=1.0. That proves only that this implementation agrees with the labels on three artificial records; it does not prove real semantic-model quality, ANN-index quality, or RAG answer quality.

Questions to answer while reading the code

  1. Why does top_k sort cosine/dot descending and Euclidean ascending?
  2. Why does cosine check both norms?
  3. Why are hand-authored relevance sets necessary for evaluation instead of being inferred from vector scores?
  4. Why does exact-search complexity grow with both document count and dimension?
  5. Why are equal scores secondarily sorted by document ID? How does that support reproducible tests?
  6. Why must _require not be replaced by a bare assert as the sole runtime validation?

Verification for this revision

Verified on 2026-07-22

Under Python 3.11.9, the script has identical output in normal and -O modes; all nine unittest cases pass in normal and -O modes with -W error. Acceptance uses only standard-library teaching data—no credentials, network, third-party dependencies, or real embedding data.

The tests cover known dot/norm/distance values; equivalence of normalized dot and cosine rankings; magnitude-induced metric ranking changes; ascending Euclidean order and stable tie breaking; Recall@k; empty/zero vectors, unequal dimensions, NaN, and infinity; invalid k, metric, and documents; and main() output.

Required extensions

  1. Multiply an irrelevant document by 100 and compare dot-product and cosine rankings.
  2. Normalize every vector first and verify that dot and cosine rankings agree.
  3. Add two queries with incomplete relevance sets, then explain the labeling bias in Recall.
  4. Use the existing Euclidean top-k to verify the ranking relationship for unit vectors, and explain the condition under which “numeric values differ but ranking is equivalent.”
  5. Record a fictitious model version for every vector; simulate mixing in another coordinate space and explain why the arithmetic still runs while the semantics are invalid.

Common errors and troubleshooting

ErrorConsequenceDiagnosis and correction
Sort cosine ascendingThe least similar result is firstState “larger similarity is better; smaller distance is better” before coding.
Normalize only the queryInner product is no longer equivalent to cosineApply the same normalization convention to query and documents.
Replace a zero vector with a tiny constant and continueHides an upstream data or model failureReject it explicitly, record its origin, and repair the generation path.
Compare floating-point results with ==Rounding makes tests fragileUse absolute/relative tolerances and test rankings and boundaries.
Generate “relevance labels” from retrieval scoresEvaluation merely repeats model preferenceBuild ground truth from the task definition and human/authoritative data.
Extrapolate exact small-data results directly to ANNIgnores index recall loss and filtering costUse exact top-k as the reference for ANN Recall@k, latency, and memory.

Mastery criteria

  • I can implement and calculate the three measures without a library.
  • I raise explicit errors for zero vectors and unequal dimensions.
  • I can sort correctly for a metric’s direction.
  • I can calculate Recall@k and explain the limits of ground truth.
  • I do not extrapolate teaching-vector results into claims about real model capability.
  • I can run normal/-O scripts and both test groups, and explain why every exception check still applies.

Return to Vector Fundamentals.

References

Sources verified on 2026-07-22.