Skip to content
datarekha

What are embeddings, and how do you measure similarity between them for vector search?

The short answer

Embeddings are learned dense vectors that place semantically related data near one another in a model-specific geometric space. Vector search embeds a query, compares it with stored vectors using a metric such as cosine similarity, dot product, or Euclidean distance, and returns the nearest candidates.

How to think about it

Embeddings are learned, dense numeric vectors that represent text, images, audio, or other data in a geometric space. Vector search turns a query into the same kind of vector, measures it against stored vectors with a metric such as cosine similarity or dot product, and returns the nearest candidates.

Why embeddings work

An embedding is a fixed-length array of numbers produced by an embedding model. “Dense” means that many coordinates carry non-zero values, unlike a sparse representation such as a word-count vector where most coordinates are zero.

For example, a model might represent a sentence with 768 numbers:

[0.12, -0.04, 0.81, ...]

Those individual coordinates usually do not have human-readable meanings. Coordinate 37 is not necessarily “password” and coordinate 212 is not necessarily “finance.” Meaning is spread across the whole vector.

The useful property comes from training. An embedding model is trained so that related inputs receive compatible representations and unrelated inputs receive less compatible ones. Many retrieval models use a contrastive objective, which pulls a query and its relevant document together while pushing the query away from irrelevant documents.

That creates geometry. “Reset my payroll password” should land closer to “Steps to reset your employee payroll password” than to “How to change the office Wi-Fi password.” The model has learned that relationship from its training data; the search system is not looking up synonyms at query time.

Common misconception: embeddings do not create a universal map of meaning. A vector is meaningful only relative to the model that produced it, its version, its preprocessing, and the metric used to compare it. A vector from one model should not be compared with a vector from another model merely because both happen to have 768 dimensions.

A concrete similarity calculation

Use this tiny example as a model of the arithmetic, not as a real language model output. Let q be a query vector, a a relevant document, and b and c two other documents.

from math import sqrt

q = (1, 2)
a = (2, 4)
b = (2, 0)
c = (10, 0)

def dot(x, y):
    return sum(xi * yi for xi, yi in zip(x, y))

def norm(x):
    return sqrt(dot(x, x))

def cosine(x, y):
    return dot(x, y) / (norm(x) * norm(y))

def euclidean(x, y):
    return sqrt(sum((xi - yi) ** 2 for xi, yi in zip(x, y)))

for name, v in [("A", a), ("B", b), ("C", c)]:
    print(
        name,
        f"cosine={cosine(q, v):.3f}",
        f"dot={dot(q, v)}",
        f"euclidean={euclidean(q, v):.3f}",
    )

The output is:

A cosine=1.000 dot=10 euclidean=2.236
B cosine=0.447 dot=2 euclidean=2.236
C cosine=0.447 dot=10 euclidean=9.220

The query q and vector a point in exactly the same direction, so their cosine similarity is 1.000. Vector c points in the same direction as b, so b and c have the same cosine similarity even though c is much longer.

That exposes the difference between the metrics:

  • Cosine similarity measures the angle between vectors. It ignores overall length.
  • Dot product, also called the inner product, measures both alignment and length.
  • Euclidean distance, often called L2 distance, measures straight-line distance between coordinates. Lower is better.

For vectors x and y, cosine similarity is:

cos(x, y) = (x · y) / (||x|| ||y||)

The terms ||x|| and ||y|| are the vectors’ lengths. Dividing by them is why cosine ignores magnitude.

What a real vector search does

A production system usually follows this sequence:

  1. Split documents into retrievable pieces called chunks. A chunk might be a paragraph, a section, or a few hundred tokens.
  2. Embed every chunk with one embedding model.
  3. Store each vector alongside its text, document ID, tenant ID, timestamp, and other metadata.
  4. Embed the user’s query with the compatible query model.
  5. Compare the query vector with the stored vectors.
  6. Return the top k results, often followed by filtering or reranking.

If there are 1,000,000 stored vectors and each has 1,536 dimensions, an exact search performs roughly 1.536 billion coordinate multiplications for one query, before accounting for additions and memory access. That can be expensive at high traffic.

An approximate nearest-neighbor index, or ANN index, is a data structure that searches likely nearby regions instead of comparing the query with every vector. It makes search much faster, at the cost of occasionally missing the true nearest vector. The relevant quality measure is recall: the fraction of the actual nearest results that the index successfully returns.

For a small corpus, exact search may be perfectly sensible. ANN is not automatically better; it adds index-building, tuning, memory, and operational complexity.

Choosing the metric

The metric should match the embedding model and the way its vectors are used.

MetricWhat it measuresImportant consequence
Cosine similarityDirection or angleVector length does not affect the score
Dot productDirection and magnitudeLonger vectors can receive higher scores
Euclidean distanceStraight-line coordinate distanceSmaller values are better

A common production pattern is L2 normalization, which scales every vector to length one. Once both query and document vectors are normalized, dot product and cosine similarity produce the same ranking. Euclidean distance does too, because for unit vectors:

||x - y||² = 2 - 2 cos(x, y)

That does not mean normalization is always correct. If the model was trained for raw dot product and magnitude carries useful information, normalizing may remove a signal the model intended you to keep. The model’s documentation and retrieval evaluation should decide, not habit.

Also check the search system’s sign convention. Some systems expose “cosine distance,” calculated as 1 - cosine similarity, where lower is better. If an engineer sorts that value as though it were a similarity score, the worst matches rise to the top. A surprisingly efficient way to ruin search.

The senior nuance: similarity is not relevance

The nearest vector is only a relevance signal. It is not proof that the result answers the question, is factually correct, is current, or is safe for the user to see.

Embedding-only search is weak for exact identifiers such as INV-84721, SKU numbers, error codes, legal clauses, and dates. A semantically similar invoice paragraph may outrank the paragraph containing the exact invoice number. Keyword search is better at exact matches, while embeddings are better at paraphrases. Many strong systems combine both in hybrid search.

Metadata filters are equally important. A support agent should not retrieve a document from another customer merely because its vector is close. Apply tenant, permission, language, and time filters as part of retrieval rather than hoping similarity will enforce them.

For high-value answers, retrieve perhaps 20 candidates and use a reranker, a model that reads the query and each candidate together, to select the best few. This costs more latency than a vector comparison, but it can reason about word order, negation, and exact details that a single vector compresses.

Do not choose a universal threshold such as “cosine above 0.8 means relevant.” Scores depend on the model, domain, chunk size, and corpus. Establish thresholds from a labeled evaluation set instead.

A failure mode to watch for

The first symptom is often that the top results look vaguely related but the precise answer sits at rank 8 or 20. Check four things:

  • The documents and queries were embedded with compatible models and versions.
  • The index uses the intended metric.
  • Normalization is consistent on both sides.
  • The chunks contain enough context to answer the question.

If documents were embedded with model A and queries with model B, a dimension mismatch may reject the vectors. If both models happen to emit the same dimension, the system may accept them while producing quietly poor rankings. Also verify whether the database returns similarity or distance and whether your application sorts in the correct direction.

What they’ll ask next

Why not always use cosine similarity?
Because dot product may be what the model was trained to optimize, and vector magnitude may carry useful information. Cosine is a strong default for directional semantic similarity, not a universal law.

Why use an approximate nearest-neighbor index?
An exact scan over 1,000,000 vectors of 1,536 dimensions requires about 1.536 billion coordinate comparisons. ANN reduces the work by searching likely neighborhoods, trading some recall for speed.

How would you improve a poor retrieval system?
I would build a labeled query set, inspect failures by category, verify model and metric compatibility, tune chunking, add metadata filters, combine lexical and vector retrieval for exact terms, and rerank when the application can afford the latency.

Say this in the interview

“Embeddings map data into a model-specific geometric space, and vector search retrieves nearby vectors using a metric such as cosine, dot product, or Euclidean distance; the right metric depends on normalization and the embedding model, and similarity must still be evaluated against real relevance.”

Learn it properly Embeddings

Keep practising

All NLP & LLMs questions

Explore further