Vectors are a data type now, and how nearest-neighbor search works
For a couple of years the advice was "use a dedicated vector database." In 2026 that advice quietly reversed. Postgres (via pgvector), MongoDB, Oracle, and others now treat a vector as a built-in column type, the way they treat a number or a string. The trend line is clear: vectors are becoming a data type, not a database category.
That makes "vector search" a thing every backend engineer will touch, so it is worth knowing what it actually is. It turns out to be one idea you have probably already met, plus one clever index to make it fast.
The one idea: search becomes geometry
A vector (an embedding) turns a thing, a document, an image, a product, into a list of numbers so that similar things sit close together in that number space (we built one in what embeddings are). Once your data is vectors, "find similar items" becomes "find the nearest points," and similarity is measured by the angle between vectors, cosine similarity:
import math
def cosine(a, b):
dot = sum(x * y for x, y in zip(a, b))
na = math.sqrt(sum(x * x for x in a))
nb = math.sqrt(sum(y * y for y in b))
return dot / (na * nb)
To search, you embed the query and find the stored vectors with the highest cosine. That is the entire concept of semantic search and RAG retrieval.
Brute force, and why it stops working
The obvious implementation compares the query against every stored vector:
def brute_force_search(query, vectors, k=3):
scored = [(cosine(query, v), i) for i, v in enumerate(vectors)]
scored.sort(reverse=True)
return scored[:k] # the k nearest
This is correct and, for a few thousand vectors, perfectly fine. The problem is scale. Every query touches every vector, and each comparison is work proportional to the vector's dimension (often 768 or 1536 numbers). That is O(n · d) per query. At a million vectors of dimension 1536, every single search does over a billion multiplications. Exact, but far too slow for real time.
The fix: approximate nearest neighbor (HNSW)
The insight that makes vector search practical: you almost never need the exact nearest neighbors, you need very good ones, fast. Giving up a tiny bit of accuracy buys orders of magnitude of speed. That is "approximate nearest neighbor" search, and the most popular index for it is HNSW (Hierarchical Navigable Small World).
The idea, without the math:
- Build a graph where each vector is a node connected to its nearby vectors. To search, start anywhere and greedily walk toward the query, always stepping to the neighbor that's closer, until you can't get closer. You explore a tiny fraction of the graph instead of scanning everything.
- Make it hierarchical: a few sparse "express lane" layers on top let you take big jumps across the space first, then drop into denser layers for the fine-grained search, like zooming in on a map. (This is the same small-world intuition as "six degrees of separation," short paths exist between any two points if you wire the graph well.)
The payoff is roughly O(log n) per query instead of O(n). A million-vector search that scanned a billion numbers now visits a few hundred nodes. The cost is that results are approximate (you might miss a true nearest neighbor occasionally) and the index uses extra memory for the graph, the usual index trade-off, the same bargain a B-tree makes for sorted lookups.
Why "vectors as a data type" matters
The reason this shift is a big deal is operational, not algorithmic. When vectors live in your existing database:
- You join vector search with your normal
WHEREfilters in one query, "nearest products to this embedding that are in stock and under $50", instead of querying a separate vector store and reconciling results. - You get transactions, backups, and access control for free, the database already has them. No second system to keep in sync.
- There is one source of truth. Your embeddings sit next to the rows they describe.
That is why pgvector challenging dedicated vector databases is the story: for most apps, "a vector column in the database you already run" beats "a whole new database." The specialized stores still win at extreme scale, but the default moved.
What you just learned
Vector search is cosine similarity plus a smart index. Brute force is a few honest lines and is the right answer until it isn't; HNSW is the graph-walk that makes it scale by trading exactness for speed. Once you see that, "vector database" stops being a black box: it is a nearest-neighbor index with a SQL interface bolted on.
Building these primitives, similarity, brute-force kNN, the index that replaces it, is exactly the kind of thing the data engineering track is about: not wiring up a service, but understanding the engine inside it.