Just Brute Force Your Embeddings

2026-08-01 · page · source ↗ · source summary

Doug Turnbull's empirically-backed case that most teams building embedding search don't need a vector database yet — a single line of NumPy on a laptop handles millions of documents at sub-15ms latency. The sweet spot is ~1M docs, low query traffic, and up-front embedding writes; past that, reach for FAISS before reaching for infrastructure.


Key Quotes

"My O(n) algorithm can run circles around your O(log n) algorithm" — Raymond Chen

Turnbull uses Chen's quip as the thesis statement and then proves it. On an M4 MacBook Pro, a single np.dot() line serves 79.7 QPS against 1M vectors at 12ms average latency. That's fast enough for most internal tools and many production use cases. The constant factors matter more than the asymptotic complexity until you're well past the million-document mark.

"An exhaustive search may be all you need" — Jo Kristian Bergum

The Vespa creator's quiet observation, quoted as corroboration. Bergum builds approximate nearest neighbor search for a living and still tells people to try brute force first. When the domain expert and the vendor both say "you probably don't need my product," pay attention.

The code: scores = self.doc_vectors @ query_vector.astype(np.float32, copy=False)

This is the entire implementation. One line of NumPy. No index builds, no configuration, no operational complexity. Turnbull's benchmarks show it scaling to 8.8M documents at 9.3 QPS single-threaded — slow for a user-facing app but perfectly fine for batch processing or internal tooling. The takeaway isn't "NumPy beats vector databases," it's "measure before you architect."


Key Themes


Critical Analysis

Turnbull is making the "SQLite is all you need" argument for vector search, and he's mostly right. The numbers are convincing: 1M documents at 12ms is real, and that covers a surprising fraction of embedding workloads. The teams that need Pinecone or Weaviate or pgvector with HNSW indexes are the ones who already know they need them — they have tens of millions of documents or hundreds of QPS. Everyone else is over-provisioning.

The benchmark methodology has some honest gaps. Single-query latency and throughput are measured, but there's no measurement of what happens when the document matrix doesn't fit in L3 cache (8.8M × 384 × 4 bytes = 13.5 GB — way past any MacBook cache). The 10-thread benchmark at that scale shows zero latency improvement over 1 thread (0.106s in both cases), which screams memory bandwidth saturation. Turnbull doesn't dig into this, though he does gesture at batching multiple queries per matrix scan as the fix.

The FAISS recommendation as the next step is the right instinct. FAISS gives you the same in-memory brute force with optional IVF/PQ acceleration, flat indexing as the default, and GPU support — but it's still "load vectors into memory and compute dot products," not "stand up a database cluster." The progression of brute force → FAISS → vector database is a ladder where each rung solves a specific scaling problem, and Turnbull's contribution is showing that the first rung is higher than most people think.

The post's real contribution isn't the benchmarks — it's the reframe. The industry default has become "you have embeddings, therefore you need a vector database." Turnbull shows that the inference doesn't hold for the median use case. Like SQLite Is All You Need, the argument is that simple tools on modern hardware cover more ground than conventional wisdom admits, and the operational cost of complexity is real even when the licensing cost is zero.

The companion piece to this would be "Just Brute Force Your Full-Text Search" — the same argument applied to BM25 vs. Elasticsearch. The pattern generalizes: measure the simple thing first, and be surprised how often it's enough.


Related Pages


Sources: raw/just-brute-force-embeddings Last updated: 2026-08-01