Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 7

Measuring Semantic Similarity

Recommended resources

Welcome back! In our last lesson, you learned how to programmatically generate text embeddings, turning raw text into meaningful numerical vectors. You now have the fundamental building blocks for a semantic search system. However, possessing these vectors is only half the story. Their true power is unlocked when we can compare them to find out which pieces of text are semantically "closest" to each other.

This lesson bridges that gap. We will explore the mathematical heart of semantic search: the metrics used to quantify the similarity between embedding vectors. You will learn not just the formulas but also the crucial intuition behind them, enabling you to understand why a particular retrieval method works. We will focus on the most common metrics used in RAG systems—cosine similarity and the dot product—and also discuss Euclidean distance to provide a complete picture. By the end of this lesson, you'll be able to calculate and interpret these similarity scores, which is the core operation for retrieving relevant documents.

The Geometry of Meaning

Imagine each embedding vector as a point in a vast, high-dimensional space. In this "semantic space," vectors representing similar concepts are located close to one another, while those for dissimilar concepts are far apart. The query "How do I train my dog?" would be near the document chunk "A guide to puppy obedience," but distant from "The history of the Roman Empire."

To quantify this "closeness," we use similarity metrics. Let's start with a visual overview of the three most common ones.

This infographic provides a high-level comparison of the three primary vector similarity metrics: Cosine Similarity, Dot Product, and Euclidean Distance. It highlights their formulas, core ideas, and key characteristics.

As you can see, each metric approaches the problem from a slightly different angle. Let's break them down one by one, starting with the most intuitive.


Euclidean Distance: The Ruler in Space

The most straightforward way to measure the distance between two points is to draw a straight line between them. This is exactly what Euclidean distance does. You are likely familiar with this from basic geometry as the Pythagorean theorem, extended to any number of dimensions.

In the context of embeddings, a smaller Euclidean distance means the vectors are closer in space and therefore more semantically similar.

While intuitive, Euclidean distance has significant drawbacks for text embeddings:

  1. Sensitivity to Magnitude: It is sensitive to the length (or magnitude) of the vectors. Two vectors could point in the exact same direction (representing very similar content), but if one is much longer than the other (perhaps from a longer document), the Euclidean distance will be large, incorrectly suggesting they are dissimilar.
  2. The Curse of Dimensionality: In very high-dimensional spaces (like the 1536 dimensions of text-embedding-3-small), our geometric intuition breaks down. Distances become less meaningful, and most points end up being far away from each other, making it difficult to distinguish close neighbors.

For these reasons, Euclidean distance is rarely the first choice for semantic search in RAG.

To see a more formal explanation and a Python implementation, please read the following section from an article by Dataquest.

Measuring Similarity and Distance between Embeddings

This article provides clear, hands-on implementations and explanations for the main similarity metrics.

Focus on the section Implementing Euclidean Distance. Pay attention to the formula and the author's note on why it can be sensitive to vector magnitude. Notice that for this metric, a lower score means higher similarity.


Cosine Similarity: Measuring the Angle of Meaning

This brings us to the most common and effective metric for semantic search: cosine similarity. Instead of measuring the straight-line distance between vector endpoints, cosine similarity measures the angle between the vectors.

The core idea is that the direction of the vector captures its semantic meaning, while its magnitude might be influenced by factors like word count, which we often want to ignore. Two vectors pointing in the same direction have a small angle between them, indicating high similarity, regardless of their lengths.

This video from StatQuest provides an excellent, clear explanation of the intuition behind cosine similarity.

Cosine Similarity, Clearly Explained!!!

StatQuest videos are famous for making complex topics easy to understand. This one is no exception and will build your intuition for cosine similarity from the ground up.

Watch the following segments: The core concept: This part visualizes how text phrases are converted to vectors and how the angle between them represents similarity. Ignoring magnitude: This is a key insight. It shows why the length of the vector doesn't affect the cosine similarity score. Interpreting the score: This explains what scores of 1 (identical), 0 (unrelated), and values in between signify.

The formula for cosine similarity is:

Where:

  • is the dot product of vectors A and B.
  • and are the magnitudes (or lengths) of vectors A and B.

The result ranges from -1 to 1:

  • 1: Vectors point in the exact same direction (perfectly similar).
  • 0: Vectors are orthogonal (unrelated).
  • -1: Vectors point in opposite directions (perfectly dissimilar).

For text embeddings, scores are almost always positive, typically ranging between 0 and 1, because documents rarely have truly "opposite" meanings. A higher cosine similarity score means the texts are more semantically similar.


Dot Product: The Efficient Shortcut

Now, let's look at the numerator of the cosine similarity formula: the dot product. The dot product is calculated by multiplying the corresponding components of two vectors and summing the results.

The dot product is influenced by both the angle between vectors and their magnitudes. A higher dot product score generally indicates higher similarity.

Here's the crucial insight for a software engineer: If the vectors are normalized to have a magnitude of 1, the denominator in the cosine similarity formula () becomes 1, and the cosine similarity becomes mathematically identical to the dot product.

Many modern embedding models, including OpenAI's text-embedding-3-small, produce normalized vectors by default. This makes the dot product an extremely efficient way to calculate similarity, as it avoids the computationally expensive square root operations needed for calculating magnitudes. This is why many optimized vector databases use dot product as their core similarity operation.

The following video clearly explains this practical relationship.

RAG Tutorial 2025 #5: Cosine Similarity for Vector Search Explained

This video from Harish Neel is part of a RAG tutorial and provides a very practical, developer-focused explanation of the link between cosine similarity and dot product.

First, watch the brief explanation of the cosine similarity formula. Then, pay close attention to the key insight section, which explains why for modern, normalized embeddings, cosine similarity simplifies to just the dot product.


Practical Implementation and Comparison

Let's solidify these concepts with code. We can use the numpy library, a standard for numerical operations in Python, to implement these calculations.

import numpy as np




# Let's define three example embeddings.
# `query` is our search query.
# `doc1` is semantically similar to the query.
# `doc2` is unrelated.
# For simplicity, we use 4-dimensional vectors. Real embeddings are much larger.

query = np.array([0.1, 0.7, 0.2, 0.5])
doc1 = np.array([0.2, 0.6, 0.3, 0.4]) # Similar to query
doc2 = np.array([0.9, 0.1, 0.1, 0.2]) # Dissimilar to query




# Let's normalize them, as is common with modern embedding models.
query_norm = query / np.linalg.norm(query)
doc1_norm = doc1 / np.linalg.norm(doc1)
doc2_norm = doc2 / np.linalg.norm(doc2)





# --- Metric Calculations ---

def calculate_metrics(vec1, vec2):



    # Cosine Similarity
    cosine_sim = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
    



    # Dot Product
    dot_product = np.dot(vec1, vec2)
    



    # Euclidean Distance
    euclidean_dist = np.linalg.norm(vec1 - vec2)
    
    print(f"Cosine Similarity: {cosine_sim:.4f}  (Higher is better)")
    print(f"Dot Product:      {dot_product:.4f}  (Higher is better)")
    print(f"Euclidean Distance: {euclidean_dist:.4f} (Lower is better)")


print("--- Comparing Query with SIMILAR Document (doc1) ---")



# Using normalized vectors, as you would in a real application
calculate_metrics(query_norm, doc1_norm)



# Notice how Cosine Similarity and Dot Product are identical for normalized vectors.

print("\n--- Comparing Query with DISSIMILAR Document (doc2) ---")
calculate_metrics(query_norm, doc2_norm)

Running this code, you'll observe:

  • The comparison between the query and the similar document (doc1) yields a high cosine similarity/dot product and a low Euclidean distance.
  • The comparison with the dissimilar document (doc2) shows the opposite: low similarity scores and a high distance.
  • Critically, for the normalized vectors, the cosine similarity and dot product values are identical, demonstrating the "shortcut" we discussed.

To get a final, consolidated view on which metric to choose, the following resources provide excellent summaries.

Measuring Similarity and Distance between Embeddings

This article again provides excellent, practical guidance.

Read the sections for Dot Product Similarity and Cosine Similarity to see how they are implemented and compared. Finally, study the summary table in the section "Choosing the Right Metric". This table is a perfect cheat sheet for deciding which metric to use in different scenarios.

RAG Explained: Understanding Embeddings, Similarity, and Retrieval

This article from Towards Data Science offers another clear, concise explanation.

Read the section "Assessing the similarity of embeddings". It does a great job of recapping the relationship between cosine similarity and dot product for normalized vectors.


Conclusion

You have now mastered the fundamental mechanism that powers semantic retrieval. By understanding how to measure the similarity between embedding vectors, you can now see how a system can find the most relevant pieces of information for a given query.

Here are the key takeaways from this lesson:

  • Similarity is Geometric: We quantify semantic similarity by measuring the "distance" or "angle" between embedding vectors in a high-dimensional space.
  • Cosine Similarity is King: For text embeddings, cosine similarity is the industry standard because it measures the angle between vectors, ignoring magnitude, which makes it robust to variations in text length. A higher score (closer to 1) means more similar.
  • Dot Product is the Efficient Shortcut: For normalized vectors (magnitude = 1), dot product is mathematically equivalent to cosine similarity and is computationally faster. This is a crucial optimization used in many vector databases.
  • Euclidean Distance is Intuitive but Flawed: While easy to understand, its sensitivity to vector magnitude and the curse of dimensionality make it less suitable for most RAG applications.

You have learned what embeddings are, how to generate them, and now, how to compare them. In our next lesson, we will put this all together to explore semantic search and contrast it with the traditional keyword-based search that you are already familiar with. This will clarify why this vector-based approach is such a revolutionary step for information retrieval.