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' -vNo 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:
| Metric | Rank 1 | Rank 2 | Ranking direction |
|---|---|---|---|
| cosine | python-api, approximately 0.9986 | http-retry, approximately 0.9948 | Larger is more similar |
| Euclidean | python-api, approximately 0.1000 | http-retry, approximately 0.2449 | Smaller 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
- Why does
top_ksort cosine/dot descending and Euclidean ascending? - Why does
cosinecheck both norms? - Why are hand-authored relevance sets necessary for evaluation instead of being inferred from vector scores?
- Why does exact-search complexity grow with both document count and dimension?
- Why are equal scores secondarily sorted by document ID? How does that support reproducible tests?
- Why must
_requirenot be replaced by a bareassertas 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
-Omodes; all nineunittestcases pass in normal and-Omodes 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
- Multiply an irrelevant document by 100 and compare dot-product and cosine rankings.
- Normalize every vector first and verify that dot and cosine rankings agree.
- Add two queries with incomplete relevance sets, then explain the labeling bias in Recall.
- 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.”
- 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
| Error | Consequence | Diagnosis and correction |
|---|---|---|
| Sort cosine ascending | The least similar result is first | State “larger similarity is better; smaller distance is better” before coding. |
| Normalize only the query | Inner product is no longer equivalent to cosine | Apply the same normalization convention to query and documents. |
| Replace a zero vector with a tiny constant and continue | Hides an upstream data or model failure | Reject it explicitly, record its origin, and repair the generation path. |
Compare floating-point results with == | Rounding makes tests fragile | Use absolute/relative tolerances and test rankings and boundaries. |
| Generate “relevance labels” from retrieval scores | Evaluation merely repeats model preference | Build ground truth from the task definition and human/authoritative data. |
| Extrapolate exact small-data results directly to ANN | Ignores index recall loss and filtering cost | Use 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/
-Oscripts and both test groups, and explain why every exception check still applies.
Return to Vector Fundamentals.
References
Sources verified on 2026-07-22.