Chapter 4 · Part 2
Rank by cosine similarity
We have eight documents as points in space, and any query becomes a point too. Search is now a geometry question: which document point is closest to the query point? The standard way to measure that for embeddings is cosine similarity — how closely two vectors point in the same direction.
Cosine similarity runs from −1 to 1: 1 means the two vectors point the exact same way (same meaning), 0 means unrelated, negative means opposite. Direction is what matters, not length — which is exactly why we normalized every vector in Chapter 3.
Score the query against every document
Because the corpus is one 8 × 384 matrix and the query is one 384 vector, a single
matrix–vector product scores the query against all eight documents at once. Add
this to search.py:
import numpy as np
query = "I can't log into my account"
query_embedding = model.encode(query, normalize_embeddings=True)
# One dot product per document = cosine similarity for all of them at once.
scores = corpus_embeddings @ query_embedding # shape (8,)
for doc, score in zip(corpus, scores):
print(f"{score:.3f} {doc}")The @ is matrix multiplication: each row of corpus_embeddings (a document) is
dotted with query_embedding, giving one score per document. Run it:
python search.py0.531 How do I reset my password?
0.198 Where can I see my past orders?
0.161 What is your refund and return policy?
0.242 How do I update my shipping address?
0.129 Do you ship internationally?
0.334 How can I contact customer support?
0.286 How do I cancel my subscription?
0.147 What payment methods do you accept?The query — "I can't log into my account" — contains none of the words reset, password, forgot. Yet the password-reset document scores highest by a clear margin. The engine matched on meaning. Now we just need to pick the winners and wrap it in a tidy function.