Semantic Similarity
Compare meaning instead of exact words by measuring distance between vectors.
Semantic similarity means how close two pieces of text are in meaning. With embeddings you measure it as the distance between their vectors.
Keyword vs. semantic search
- Keyword search matches exact words. A search for "car" misses a document that says "automobile".
- Semantic search matches meaning. "car" and "automobile" have nearby vectors, so both are found.
The recipe
- Embed the query.
- Compare it to the embeddings of your documents.
- Return the closest ones.
Example
{
"query": "how do I reset my password",
"most_similar_docs": [
{"title": "Recovering account access", "score": 0.91},
{"title": "Changing your login credentials", "score": 0.88},
{"title": "Billing FAQ", "score": 0.34}
]
}When to use it
- A customer-support system finds the most semantically similar past support ticket to a new incoming query and suggests its resolution.
- A plagiarism checker uses semantic similarity to flag paraphrased content even when no exact words are shared.
- A recipe recommendation engine finds recipes semantically close to a user's description like 'quick pasta with vegetables' without relying on tags.
More examples
Find the most similar sentence
Embeds a query and candidates, then picks the candidate with the highest cosine similarity.
from openai import OpenAI
from numpy import dot
from numpy.linalg import norm
client = OpenAI()
def embed(text):
return client.embeddings.create(
model='text-embedding-3-small', input=text
).data[0].embedding
def cosine(a, b):
return dot(a, b) / (norm(a) * norm(b))
query = 'How do I reset my password?'
candidates = [
'Steps to recover your account access.',
'How to bake sourdough bread.',
'Resetting login credentials guide.',
]
q_vec = embed(query)
scores = [(c, cosine(q_vec, embed(c))) for c in candidates]
best = max(scores, key=lambda x: x[1])
print('Best match:', best[0], f'(score={best[1]:.3f})')Semantic vs keyword search contrast
Illustrates why keyword search fails on paraphrases and why semantic search is needed.
# Keyword search misses this match
query = 'affordable smartphones'
docs = ['budget mobile phones', 'luxury watches', 'cheap tablets']
keyword = [d for d in docs if any(w in d for w in query.split())]
print('Keyword match:', keyword) # [] β misses 'budget mobile phones'
# Semantic search would find 'budget mobile phones' via embedding similarity
# (embedding call omitted for brevity, but cosine score would be highest for it)
print('Semantic search would find: budget mobile phones')Rank all candidates by similarity
Ranks all candidate documents by cosine similarity to a query, showing the top match first.
from openai import OpenAI
from numpy import dot
from numpy.linalg import norm
client = OpenAI()
def embed(text):
return client.embeddings.create(
model='text-embedding-3-small', input=text
).data[0].embedding
cosine = lambda a, b: dot(a, b) / (norm(a) * norm(b))
query = 'machine learning basics'
docs = ['intro to deep learning', 'baking recipes', 'neural network fundamentals', 'gardening tips']
q_vec = embed(query)
ranked = sorted(docs, key=lambda d: cosine(q_vec, embed(d)), reverse=True)
for rank, doc in enumerate(ranked, 1):
print(f'{rank}. {doc}')
Discussion