liveBook · Manning

Cosine similarity

As explained in AI-Powered Search

Cosine similarity measures the angular similarity between two vectors by dividing their dot product by the product of their magnitudes.

A search query and a document can each be represented as a vector: a list of numbers describing feature strengths. Cosine similarity compares their directions to produce a score for ranking documents. The same measure can compare dense embeddings that encode the meaning of phrases or items. section 3.1 section 2.3

Calculate it by dividing the vectors’ dot product by the product of their magnitudes: cosine similarity = dot(query, document) / (magnitude(query) × magnitude(document)). The dot product rewards features shared by both vectors; dividing by their lengths scales the result. Compute a score for each document, then sort by score. section 2.3 section 3.1.2

Why matching every query term may still leave a tie

For the query “apple juice,” two documents receive the same cosine score, 0.2828, when compared using their longer term vectors. Restricting all three vectors to the two query-term features gives [1, 1] for each and a score of 1.0 for each document. The absolute scores change because the representations change; neither calculation distinguishes the documents. Feature selection and weighting therefore matter alongside the similarity formula. section 3.1.2 section 3.1.3

Listing 3.1 Calculating cosine similarity between vectors
query_vector = numpy.array(
  [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

doc1_vector = numpy.array(
  [0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1,
   0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0])

doc2_vector = numpy.array(
  [1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
   1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1])

def cosine_similarity(vector1, vector2):
  return dot(vector1, vector2) / (norm(vector1) * norm(vector2))

doc1_score = cosine_similarity(query_vector, doc1_vector)
doc2_score = cosine_similarity(query_vector, doc2_vector)

print_scores([doc1_score, doc2_score])

Inspect the NumPy vectors and cosine_similarity function to see how query–document scores are computed. section 3.1.2

For semantic comparisons, encode phrases as dense embeddings, normalize each embedding to unit length, and take dot products to obtain cosine similarities. A four-phrase example ranks “it's raining hard” closest to “it is wet outside.” Comparing every phrase with every other phrase creates a square similarity table, so its computation and storage costs grow as the number of phrases grows. section 13.4.3

How AI-Powered Search covers it

How deep it goes
Works through the formula, a NumPy calculation, sparse query-term features, and normalized embedding comparisons; it does not develop the linear algebra further here.
Examples
Compares food-item embeddings, scores two documents for “apple juice,” and ranks four encoded phrases.
What it assumes
Introduces vectors as lists of feature strengths and shows the calculation before extending it to encoded phrases.
What you can do after
Apply it via NumPy to score query–document vectors, or via SentenceTransformers embeddings and dot scores to rank phrase similarities.
How it connects
Connects cosine similarity to dense embeddings, sparse vector representations, feature weighting, and relevance ranking.

Also explained in

Compare how 14 books explain cosine similarity →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of AI-Powered Search. The section links point to the parts of the book it draws on.