An embedding turns text, images, or code into a vector that captures meaning, so semantically similar things land close together in space. A vector database indexes those vectors and finds nearest neighbors in milliseconds, even across billions of items. Together they are the engine behind semantic search, recommendations, deduplication, and RAG.
An embedding is a list of numbers - a vector - that represents the meaning of a piece of content. An embedding model maps inputs into a shared high-dimensional space where distance encodes similarity: two paraphrases sit near each other, unrelated sentences sit far apart. A vector database stores these vectors and answers the question "which items are closest to this one?" quickly, using an approximate nearest neighbor index.
A model turns each item into a fixed-length vector, for example 768 or 1536 floats, that captures its meaning.
Vectors are stored in a vector database with an ANN index and metadata, ready for fast similarity search.
A query is embedded the same way; the database returns the nearest neighbors ranked by a similarity metric.
| Piece | What it does | Common choices |
|---|---|---|
| Embedding model | Maps content to a vector capturing meaning | text-embedding-3, bge, e5, CLIP |
| Dimensionality | Length of the vector; sets capacity and cost | 384, 768, 1024, 1536, 3072 |
| Similarity metric | Scores how close two vectors are | Cosine, dot product, Euclidean (L2) |
| ANN index | Finds near neighbors without scanning all | HNSW, IVF, IVF-PQ, ScaNN |
| Vector store | Persists vectors, metadata, and the index | pgvector, Pinecone, Weaviate, Qdrant, FAISS |
Keyword search matches characters; embeddings match meaning. That single shift unlocks semantic search, recommendations, clustering, and the retrieval half of every RAG system, without hand-tuned rules.
"How do I reset my password" finds "steps to recover your login" even with zero shared words, because the vectors are close in meaning.
Text, code, images, and audio can share an embedding space, so you can search across modalities and languages with the same query.
ANN indexes answer nearest-neighbor queries over millions or billions of vectors in single-digit milliseconds, far faster than brute force.
Embed once and reuse the vectors for search, deduplication, clustering, recommendation, and RAG - the same representation powers many features.
Same idea, four ways to picture it, so it clicks whoever you are.
An embedding is like giving every idea a set of coordinates. Ideas about the same topic end up sitting close together on the map, so "find related notes" becomes "find the nearest dots."
Think of it as a hash that preserves similarity. Unlike a normal hash, near-identical inputs produce near-identical vectors, so you can index them and query by distance instead of exact match.
It is a smart filing system where documents are shelved by topic rather than by title. You hand it a question and it walks straight to the right shelf, no exact wording required.
A library floor map where similar books sit near each other. Once you find one good book, everything relevant is within arm's reach on the same aisle.
There are two phases: an offline indexing phase that embeds and upserts your data, and an online search phase that embeds a query and finds its nearest neighbors through an approximate index.
Load content, embed each item into a vector, and upsert the vector plus metadata into the store. The database builds an ANN structure such as HNSW or IVF so queries avoid scanning everything.
Embed the query with the same model, pick a metric such as cosine, and traverse the index for the top-k nearest vectors, optionally filtered by metadata like tenant, language, or date.
flowchart LR
subgraph Index["๐ฆ Offline indexing"]
D["๐ Items"] --> EM1["๐ข Embed"]
EM1 --> UP["โฌ๏ธ Upsert"]
UP --> VDB[("๐๏ธ Vector DB")]
VDB --> ANN["๐ธ๏ธ ANN index (HNSW / IVF-PQ)"]
end
subgraph Search["โก Online search"]
Q["โ Query"] --> EM2["๐ข Embed query"]
EM2 --> MF["๐ท๏ธ Metadata filter"]
MF --> NN["๐ ANN nearest neighbors"]
ANN --> NN
NN --> RES["โ
Top-k results + scores"]
end
from openai import OpenAI
client = OpenAI()
def embed(texts):
r = client.embeddings.create(model="text-embedding-3-small", input=texts)
return [d.embedding for d in r.data]
# 1. Embed documents and upsert into the vector store
docs = ["reset your password", "cancel a subscription", "export invoices"]
vectors = embed(docs)
index.upsert([
{"id": f"doc-{i}", "values": v, "metadata": {"text": docs[i]}}
for i, v in enumerate(vectors)
])
# 2. Embed the query and search for nearest neighbors
q_vec = embed(["how do I change my login credentials"])[0]
hits = index.query(vector=q_vec, top_k=5, metric="cosine",
filter={"lang": "en"})
for h in hits.matches:
print(round(h.score, 3), h.metadata["text"])
The same model must embed both documents and queries so their vectors share one space. The metric (cosine here) defines closeness, and the metadata filter narrows the candidate set before the nearest-neighbor search runs.
Three views: building the index, a query-time similarity search, and a hybrid search that fuses dense and keyword results with reranking.
sequenceDiagram
autonumber
participant Src as ๐ Source items
participant Pipe as โ๏ธ Index pipeline
participant Emb as ๐ข Embedding model
participant VDB as ๐๏ธ Vector DB
Src->>Pipe: Load items (docs, rows, images)
loop for each item
Pipe->>Emb: embed(item)
Emb-->>Pipe: vector plus metadata
end
Pipe->>VDB: upsert(vectors + metadata)
VDB->>VDB: Build ANN index (HNSW or IVF-PQ)
VDB-->>Pipe: index ready
Note over Pipe,VDB: Re-embed only items that changed
sequenceDiagram
autonumber
participant U as ๐ค Client
participant App as ๐ฅ๏ธ Search app
participant Emb as ๐ข Embedding model
participant VDB as ๐๏ธ Vector DB
U->>App: Send query text
App->>Emb: embed(query)
Emb-->>App: query vector
App->>VDB: search(vector, top_k, filter)
VDB->>VDB: Traverse ANN index by cosine
VDB-->>App: top-k neighbors + scores
App-->>U: Ranked results
Note over App,VDB: Higher ef or nprobe means better recall, more latency
sequenceDiagram
autonumber
participant U as ๐ค Client
participant App as ๐ฅ๏ธ Search app
participant VDB as ๐๏ธ Vector DB
participant KW as ๐ค Keyword index
participant RR as ๐ Reranker
U->>App: Query
par dense path
App->>VDB: ANN search (semantic)
VDB-->>App: dense candidates
and keyword path
App->>KW: BM25 search (lexical)
KW-->>App: keyword candidates
end
App->>App: Fuse lists (RRF)
alt reranker enabled
App->>RR: rerank(query, fused set)
RR-->>App: reordered by relevance
else score only
App->>App: keep fused order
end
App-->>U: Final ranked results
From raw content to fast, filtered semantic search - the whole journey in order.
Pull together the items you want searchable - documents, catalog rows, images - and clean them into consistent, embeddable units.
Pick a model that fits your domain, languages, and modality, and note its dimensionality and cost. Every item and query will use this same model.
Run each item through the model to get a fixed-length vector that captures its meaning in high-dimensional space.
Choose cosine, dot product, or Euclidean. Normalize vectors so cosine and dot product agree, and match the metric your model was trained for.
Write each vector with its metadata (source, tenant, language, timestamp) into the vector database, keyed by a stable id for later updates.
The database builds an approximate index - HNSW graph, IVF lists, or product quantization - so searches skip most of the data.
A request arrives; embed the query with the same model so its vector lives in the same space as the indexed items.
Restrict the search by attributes like user, language, or date so results respect permissions and relevance before neighbors are scored.
Traverse the ANN index for the top-k closest vectors. Tune ef or nprobe to trade a little latency for higher recall.
Combine semantic and keyword hits with reciprocal rank fusion, then optionally rerank with a cross-encoder for precision.
Deliver ranked, scored results to the app. Re-embed changed items, watch recall and latency, and scale shards as the corpus grows.
Most vector-search problems trace back to the embedding step or index configuration, not the database itself.
Embedding documents with one model and queries with another, or upgrading the model without re-embedding everything, puts vectors in incompatible spaces and search quality collapses.
Using dot product on unnormalized vectors lets magnitude dominate meaning, and mixing metrics between index and query gives silently wrong rankings. Match the metric the model expects.
Cranking recall parameters like ef or nprobe too low saves latency but drops relevant neighbors; too high wastes compute. Measure recall against exact search before shipping.
Searching without tenant or permission filters leaks data across users and floods results with irrelevant items. Filter first, then rank by similarity.
Forgetting to re-embed and upsert changed items serves outdated vectors, so results drift from the real content. Treat the index as a living, versioned asset.
Defaulting to the largest vector size multiplies storage, memory, and query cost with little quality gain. Right-size dimensions and use quantization when the corpus is large.
Judge retrieval quality and system efficiency separately, so you know whether to fix the model, the index, or the hardware.
| Metric | What it tells you | Good sign |
|---|---|---|
| Recall@k vs exact | How many true nearest neighbors the ANN index returns | High: approximation loses little |
| Precision / MRR / nDCG | Whether the top results are actually relevant and well ordered | High: users see the right items first |
| Query latency (p95) | Tail response time under real load | Low and stable within your SLA |
| Queries per second | Throughput a shard or node sustains | Meets peak traffic with headroom |
| Memory & storage / vector | Footprint driven by dimensionality and quantization | Fits budget after PQ compression |
| Index build / upsert time | Cost to add or refresh items in the index | Fast enough for your update rate |
Three representative patterns showing embeddings and vector search in production-style use.
An e-commerce team wants shoppers to find products by intent, not exact keywords, across a large multilingual catalog.
A content platform needs to catch reposted articles, spam variants, and near-identical support tickets at scale.
A knowledge team builds an assistant that answers from internal docs, and embeddings power the retrieval step.
Embedding models and vector infrastructure are maturing fast, pushing search to be cheaper, richer, and more adaptive.
Matryoshka-style embeddings let one model emit vectors you can truncate, trading precision for cost without re-embedding your corpus.
Shared text, image, audio, and video spaces make cross-modal search - query with text, retrieve an image - a first-class feature.
Binary and product quantization shrink vectors by orders of magnitude while keeping recall high, making billion-scale search affordable.
Dense plus lexical retrieval with rank fusion becomes the default, giving both semantic recall and exact-term precision out of the box.
Native vector types in general-purpose databases like Postgres blur the line between search infrastructure and your primary store.
Token-level models such as ColBERT rerank with fine-grained matching, closing the gap between fast ANN recall and precise relevance.