Embeddings on the Lakehouse: What Snowflake and Databricks Actually Do (and Don't) | |||||||||||||||||||||||
| |||||||||||||||||||||||
| If you're standing up Retrieval-Augmented Generation (RAG) on top of a data warehouse or lakehouse, the marketing decks make it sound simple: "native vector search, built right in." That's true — but the details matter enormously, and a lot of intuitions people bring from relational databases quietly break when they hit vectors. This post walks through the questions that actually come up when you start wiring AI into Snowflake, Databricks, or a similar platform: how the platforms differ, what embeddings really are, why "generate an embedding" is not the same as "search embeddings," and how to keep the whole thing from going stale as your data changes.
The two platforms, in briefDatabricks is a lakehouse built on Spark and open table formats (Delta Lake, and increasingly Iceberg). It's code-first — Python, Scala, SQL, notebooks — and it leans toward data engineering and machine learning. Governance and lineage run through Unity Catalog, and the ML lifecycle (MLflow, Mosaic AI) is native. It shines on unstructured, large-scale, and streaming data, and it gives you a lot of engineering flexibility. Snowflake started as a cloud data warehouse and has extended toward the lakehouse pattern. It's SQL-first and almost fully managed, which lowers the barrier to entry. It separates storage from compute, handles concurrency well through multi-cluster warehouses, and excels at structured data and BI workloads. Snowpark brings Python and ML into the fold, and Cortex adds built-in LLM and embedding functions. Both separate storage from compute, scale elastically, and bill by consumption. The rough rule of thumb: Snowflake is easier to adopt for SQL, BI, and structured work; Databricks offers more flexibility for ML, unstructured data, and custom engineering.
What to consider when you bolt AI onto either oneBefore getting into vectors specifically, the questions worth asking of any EDW/lakehouse-plus-AI setup:
Do the platforms generate embeddings themselves?Yes — both do. But an important nuance: they aren't training bespoke embedding models from scratch. They expose managed functions and APIs that call foundation models (their own hosted open models, or external providers).
So the mental model isn't "the platform invented an embedding algorithm." It's "the platform gives you a convenient, managed way to run a foundation embedding model." Databricks gives you more room to bring a domain-specific, fine-tuned model; Snowflake gives you more simplicity. Either way, the vector these functions produce is an embedding — that's exactly what the word means.
Generating embeddings ≠ supporting similarity searchHere's the first place intuition trips people up. Being able to call an embedding function does not by itself mean the platform does similarity search. Those are different layers of the stack:
If you only have step 1, you can produce vectors but you can't search them. With steps 1 through 3, you can run a brute-force search — In practice:
When you evaluate any platform, check the three things separately: is there an embedding function, is there a vector type plus distance function, and is there an ANN index? That tells you exactly how far it goes.
A common misconception: "ANN is standard, so I can plug in any vector DB"It's tempting to reason that because ANN algorithms are well-known, doing ANN means you can freely interoperate with an external vector DB. That mixes up two separate things. ANN is a family of algorithms, not an interoperability standard. HNSW, IVF, and PQ are public methods, but each system — Pinecone, Weaviate, Cortex Search, Databricks Vector Search — implements them in its own engine, with its own index format, API, and storage. "Both use HNSW" doesn't mean their indexes are compatible. It's not a wire protocol like TCP/IP; it's just a technique each vendor builds independently. What actually moves between systems is the vector data, not the index. Integration happens through connectors and pipelines: you generate embeddings in Snowflake or Databricks, then export/sync those vectors into, say, Pinecone, where they get re-indexed from scratch.
The one-liner: vectors move; indexes don't. Interoperability comes from pipelines, not from a shared standard.
Are the embeddings deterministic? Are they unique?Two different questions hide inside "does the platform guarantee consistent, unique embeddings?" Determinism (same input → same vector?) — Mostly yes, given the same model version. A trained embedding model is a fixed-weight function; inference is a forward pass with no randomness. But you can't claim "always bit-for-bit constant," because:
So "the value can differ" really means "the last decimal place can differ," not "you get a different embedding." The practical takeaway: don't use an embedding vector as an exact-match key — floating-point drift can make matches fail. Use a hash of the source text for that. And the variable that actually matters isn't float noise; it's keeping the model version fixed across indexing and querying. Uniqueness (different input → guaranteed different vector?) — No, and this isn't a bug. Embeddings aren't hashes; their purpose is semantic similarity, not uniqueness. "The dog runs" and "the canine sprints" are different inputs that deliberately map to nearly overlapping vectors — that's the whole point. Distinct inputs can even collide onto near-identical vectors. If you need unique identification, use a separate hash or primary key.
Reranking: does it delete the existing embeddings?No. Reranking is a reordering step; it doesn't remove or replace anything. RAG retrieval is usually two stages:
The reranker generally doesn't even use the stored vectors — it takes the query and each candidate document as a text pair and scores relevance on the spot. It needs the embedding search to run first, in order to have candidates to rank. So the two are collaborators, not competitors: embeddings pick the candidates; the reranker puts them in order. Embeddings get deleted for entirely separate reasons — the source document changed, the model version was swapped, or the chunking strategy changed. That's data lifecycle management, which brings us to the last and most practical topic.
Keeping embeddings fresh when data changesData changes. Embeddings computed from that data go stale. The goal is a pipeline that detects what changed, re-embeds only that, and updates the index — without recomputing everything. First, distinguish three kinds of change, because they demand different responses:
For the common case (content changes), the principle is incremental processing. Detect changes via:
Then apply three operations: upsert changed chunks, delete embeddings for removed documents, and insert new ones. Miss any of these and you get stale results.
The scalar-driven designA clean way to run this is to fix a couple of scalar columns ahead of time and drive delete/insert off them. Two scalars, two jobs:
The update logic becomes:
This is exactly the "predefine a scalar and use it to delete and add" pattern, and it's the standard design. The essential guardrail: the key must be a stable, text-based scalar (an ID or content hash), never the embedding vector itself — because of the floating-point drift discussed earlier. Vectors are for search; scalars are for management.
How each platform helps
The model-version case deserves special handlingYou can't partially update when the model changes — old and new vectors in one index make similarity meaningless. Re-embed everything, and in practice do it blue-green: build a brand-new index with the new model, validate it, switch query traffic over in one move, then retire the old index. No downtime.
Putting it togetherThe through-line of all of this:
Get the layering right, keep the model version pinned, and manage the lifecycle with stable scalar keys, and the "native vector search, built right in" promise actually delivers.
| |||||||||||||||||||||||
| | |||||||||||||||||||||||
| |