SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Assembling and Deploying Applications

Databricks GenAI Engineer: Mosaic AI Vector Search Indexes, Endpoints, Querying and Sizing

17 min readDatabricks GenAI · Assembling and Deploying ApplicationsUpdated

Mosaic AI Vector Search is Databricks' serverless vector database: it holds embeddings in Unity Catalog-governed indexes on dedicated endpoints and returns the rows most similar to a query, which makes it the retrieval layer of RAG applications and agents on Databricks. This lesson covers its two building blocks (endpoints and indexes), the Delta Sync and Direct Vector Access index types, how to create and query an index from Python and SQL, how sync modes keep an index current, how similarity scores are computed, and how to choose the endpoint type and sync mode from the number of embeddings, update frequency, latency and cost a solution requires.

What you’ll learn
  • Explain how Vector Search endpoints and indexes relate, including the per-endpoint index limit and that indexes are Unity Catalog objects
  • Choose between Delta Sync (Databricks-computed or self-managed embeddings) and Direct Vector Access for a stated data flow
  • Create a Delta Sync index with the correct embedding arguments and keep it current with triggered sync, continuous sync, or upsert and delete calls
  • Query an index with similarity_search and vector_search(), choosing query_text or query_vector, columns, num_results, filters and query type
  • Interpret similarity scores from HNSW with L2 distance and normalize vectors for cosine-equivalent ranking
  • Configure endpoint type, sync mode and throughput for a workload's vector count, update frequency, latency and cost
  • Grant the Unity Catalog privileges a service principal needs to query an index

What Mosaic AI Vector Search is: endpoints and indexes

Mosaic AI Vector Search is Databricks' serverless vector database: it stores embeddings in an approximate-nearest-neighbor index and returns the rows most similar to a query, which is the retrieval step of a RAG application or agent. Recent Databricks documentation also calls it Databricks AI Search (formerly Vector Search); the exam guide uses the Mosaic AI Vector Search name, and the core method names (create_delta_sync_index, similarity_search, sync, upsert) are the same.

It has two resources, and the exam expects you to keep them apart:

ResourceWhat it isKey facts
Vector Search endpointThe serving compute that answers queriesStandard or storage-optimized type; one endpoint hosts up to 50 indexes; it bills while it hosts indexes, even with no traffic; workspace permissions CAN CREATE / CAN USE / CAN MANAGE
Vector indexThe searchable copy of your vectors and synced columnsA Unity Catalog object named catalog.schema.index; created on one endpoint; governed with Unity Catalog grants like a table

The relationship runs one way: an endpoint hosts many indexes, and each index lives on exactly one endpoint. They are created, governed and deleted separately. The 50-index limit applies whatever the endpoint type, index type or throughput setting, so when an endpoint is full the answer is another endpoint, not a bigger one. (Limits such as this one are Databricks product limits that can change; check the current documentation for exact figures.)

The index types: Delta Sync versus Direct Vector Access

Vector Search has two index types, distinguished by where the data comes from: a Delta Sync index follows a Delta table, and a Direct Vector Access index is written directly by your code. Delta Sync then splits again by who computes the embeddings.

Index typeSource of rowsWho embedsHow it changesQuery with
Delta Sync, Databricks-computed (managed) embeddingsA Unity Catalog Delta table with a text columnDatabricks, through a named embedding model serving endpoint, at sync and at query timeSync from the table (triggered or continuous)query_text (Databricks embeds it)
Delta Sync, self-managed embeddingsA Delta table that already has an array<float> vector columnYou, in your own pipelineSync from the table (triggered or continuous)query_vector embedded by you with the same model
Direct Vector AccessNo source table: a schema you defineYou (it has no managed-embedding mode)Only your upsert and delete API callsquery_vector

Choose by the constraints in the scenario:

  • No embedding pipeline and no wish to write one: Delta Sync with Databricks-computed embeddings.
  • Vectors already in the table (for example from a fine-tuned model) and no budget to embed twice: Delta Sync with self-managed embeddings.
  • Records arrive from an application or stream and there is no Delta table, and the team accepts writing upsert code: Direct Vector Access.

Preparing the source table itself (chunking, a unique primary key, enabling change data feed) is covered in the data preparation lessons; here the point is that Delta Sync needs that table and Direct Vector Access does not have one.

Creating a Delta Sync index

You create a Delta Sync index with create_delta_sync_index (or the UI or REST API), naming the endpoint, the source table, the index name, the sync mode, the primary key, and one of two embedding argument pairs:

Embedding modeArgumentsMeaning
Databricks-computedembedding_source_column + embedding_model_endpoint_nameThe text column to embed, and the serving endpoint whose model embeds it (and embeds query_text later)
Self-managedembedding_vector_column + embedding_dimensionThe column that already holds vectors, and their length

The pairs do not mix: a text column is never an embedding_vector_column, and a dimension without a vector column describes nothing.

client.create_delta_sync_index(
    endpoint_name="manuals-endpoint",
    source_table_name="main.docs.manual_sections",
    index_name="main.docs.manual_sections_idx",
    pipeline_type="TRIGGERED",
    primary_key="section_id",
    embedding_source_column="section_text",
    embedding_model_endpoint_name="manuals-embedder",
)

Other arguments and options to know:

  • pipeline_type: "TRIGGERED" or "CONTINUOUS" (see the next section).
  • columns_to_sync: limits which source columns are copied into the index (the primary key and embedding column are always included). It is fixed at creation and is not supported on storage-optimized endpoints, which sync every column.
  • Save computed embeddings: for an index with Databricks-computed embeddings, this option writes the vectors Databricks computed to a Unity Catalog table named after the index with _writeback_table appended. It is the way to reuse those vectors (for clustering or analysis) without paying to embed again; the source table never receives them. The table is managed with the index, is deleted with it, and should not be modified.
  • Storage-optimized endpoints also require an embedding dimension divisible by 16.

A Direct Vector Access index is created instead with create_direct_access_index, giving a primary key, the vector column, its dimension and a schema for the stored columns.

Keeping an index current: triggered sync, continuous sync and direct writes

How an index picks up new data depends on its type and, for Delta Sync, on its sync mode.

ModeWhen the index updatesCostFits
Delta Sync, triggeredOnly when you call sync() (SDK or REST) or press Sync now in the UIMost cost-effective: compute runs only during a syncBatch-updated tables: call sync() as the final task of the job that writes the table
Delta Sync, continuousWithin seconds of each table change, via an always-running streaming pipelineHigher: the pipeline's cluster runs all the timeTables edited throughout the day where the index must reflect edits almost immediately
Direct Vector AccessImmediately, when your code calls upsert or deleteNo sync pipelineApplications that already own the write path

Three behaviours that scenarios turn on:

  • Triggered indexes do not watch the table. New rows written to the source table are invisible until the next sync, because maintenance or metadata operations on the table itself do not touch the index; only a sync does.
  • Direct Vector Access indexes have no link to any table. Deleting a record in the application's database leaves it in the index; you must call the index's delete API with the primary keys. sync() and change data feed only apply to Delta Sync.
  • Storage-optimized endpoints support only triggered sync. A continuous index must live on a standard endpoint.

Changing the schema or the embedded column

An existing Delta Sync index does not accept source schema changes or a switch to a different embedding column. The documented approach is to build a new index, switch the application to it once it has synced, then delete the old one. Deleting first, even to reuse the name, leaves users with failed searches until the rebuild finishes. Changing the embedding model itself is covered in the embedding-model lesson; it also requires a re-embedded index.

How similarity is measured: HNSW, L2 distance and the returned score

Vector Search finds neighbors with HNSW (an approximate nearest-neighbor graph) and measures closeness with L2 (Euclidean) distance. The score it returns is a similarity derived from that distance:

score = 1 / (1 + d²), where d is the L2 distance between the query vector and the stored vector.

Cosine similarity through normalization. Many embedding models are meant to be compared by cosine similarity. If both stored and query vectors are normalized to unit length, ordering by L2 distance gives the same order as cosine similarity, so normalize embeddings before writing them (and normalize query vectors the same way). Endpoint type, query type and numeric precision do not change the metric.

The score is not the cosine. For unit vectors, d² = 2 − 2 × cos. To turn a cosine cut-off into a score cut-off, substitute: a cosine of 0.7 gives d² = 0.6 and a score of 1 / 1.6 = 0.625. Filtering returned scores against the raw cosine value would discard relevant results.

Choosing an endpoint type: standard versus storage-optimized

Choose the endpoint type from the number of vectors, the latency and throughput target, and cost. The figures below are Databricks' published guidance at the time of writing; they change, so treat them as orders of magnitude.

Standard endpointStorage-optimized endpoint
CapacityAbout 320 million vectors at 768 dimensions; capacity falls as dimension rises (roughly half, about 160 million, at 1536). A Direct Vector Access index holds far fewer (about 2 million at 768 dimensions)More than a billion vectors
Query latencyTens of millisecondsA few hundred milliseconds
ThroughputHigher; scalable with target_qpsModest
Cost per vectorHigherMuch lower (Databricks cites up to several times cheaper)
Sync modesTriggered and continuousTriggered only
columns_to_syncSupportedNot supported (all columns sync)
Filter syntaxDictionarySQL-like string

Reading a scenario:

  • Customer-facing, tight latency, high QPS, index within capacity: standard. If load tests return HTTP 429 errors at peak, the fix is more provisioned serving capacity, which on a standard endpoint means setting target_qps (at extra cost); client-side changes only reshape the same load. target_qps raises throughput, not vector capacity.
  • Hundreds of millions to billions of vectors, latency of around half a second acceptable, low concurrency, tight budget: storage-optimized with triggered sync.
  • Fits on either: let cost and latency decide. If the latency budget allows a few hundred milliseconds and traffic is light, storage-optimized is cheaper.
  • Raising the embedding dimension shrinks how many vectors a standard endpoint holds. A corpus that fits at 768 dimensions can overflow at 1536. Keep the latency requirement fixed when you solve that: an option that makes room by giving up the latency or throughput the scenario demands does not meet it.

Controlling cost and latency

Most Vector Search cost comes from endpoints that exist and sync pipelines that run, and most avoidable latency comes from authentication, oversized requests and the embedding endpoint.

Cost levers

  • Idle endpoints still bill. An endpoint hosting indexes incurs serving cost with no queries; Vector Search endpoints do not scale to zero. Consolidate small, lightly used indexes onto one endpoint (up to 50 per endpoint) and delete the empty endpoints.
  • Prefer triggered sync when the table changes on a schedule; continuous sync runs a streaming cluster all the time.
  • Use storage-optimized endpoints for large, latency-tolerant indexes, since they cost less per vector.
  • target_qps and num_results do not reduce base serving cost; target_qps adds capacity and cost.

Latency levers

  • Authenticate with OAuth tokens for a service principal rather than personal access tokens. PATs add hundreds of milliseconds per query; OAuth uses network-optimized routing.
  • Request only the results you use with num_results (Databricks suggests 10 to 100 for most RAG use); more results means slower queries.
  • Use ANN unless keyword matching is needed; hybrid search costs extra resources.
  • Do not let the embedding endpoint scale to zero. With Databricks-computed embeddings, every query_text is first embedded by the model serving endpoint; if that endpoint has scaled to zero, the first queries after a quiet period can be slow or time out while the Vector Search endpoint itself looks healthy.
  • Separate the query embedding endpoint. A managed-embedding index can use a different serving endpoint for query embeddings (model_endpoint_name_for_query in the SDK) while the configured endpoint embeds ingestion. Heavy backfills then no longer starve user queries. The query endpoint must serve the same model, or query vectors land in a different space and retrieval quality changes.

Who can query an index: Unity Catalog privileges

Because an index is a Unity Catalog object, querying it as a non-owner requires USE CATALOG on the catalog, USE SCHEMA on the schema and SELECT on the index. This applies to a service principal that an agent or serving endpoint runs as.

  • SELECT on the source table does not grant access to the index; the query reads the index, not the table.
  • SELECT granted at the schema level works, because it is inherited by every object in the schema, but it grants far more than one index, so it fails a least-privilege requirement.
  • Endpoint permissions (CAN CREATE, CAN USE, CAN MANAGE) are workspace ACLs on the compute. CAN USE lets a user create indexes on the endpoint; it is not what authorizes reading an index's data.

Passing the end user's identity through to retrieval (on-behalf-of-user authorization) and serving-endpoint access control are covered in their own lessons.

Tip. Expect scenario items that give a corpus size, embedding dimension, update pattern, latency or QPS target and budget, then ask for the endpoint type, sync mode or combination that fits, sometimes as a select-two. Other items show a create_delta_sync_index or similarity_search call, a filter, or a vector_search() query and ask which arguments are right or what change fixes an error, so know which argument pairs belong to which index type and which features each endpoint type lacks. Operational items describe a symptom (rows missing after a batch load, deleted records still returned, empty filtered results, first-query timeouts, 429 errors, steady idle charges, a permission error) and ask for the fix. Expect a calculation of a score threshold from a cosine cut-off, and questions on the endpoint-index relationship and the privileges needed to query an index.

Key takeaways
  • An endpoint is serving compute that hosts up to 50 indexes; each index is a Unity Catalog object governed with grants.
  • Delta Sync follows a Delta table (Databricks-computed or self-managed embeddings); Direct Vector Access has no table and changes only through upsert and delete calls.
  • Databricks-computed embeddings: embedding_source_column + embedding_model_endpoint_name, query with query_text. Self-managed: embedding_vector_column + embedding_dimension, query with query_vector from the same model.
  • Triggered sync updates only when sync() or Sync now runs and is the cheapest mode; continuous sync is near real time but runs a cluster all the time and is standard-endpoint only.
  • Schema or embedding-column changes need a new index: create it, switch the app, then delete the old one.
  • Filters are a dictionary on standard endpoints and a SQL-like string on storage-optimized endpoints, where very selective filters can return nothing because of overfetch-then-filter.
  • Scores are 1 / (1 + squared L2 distance); normalize vectors for cosine-equivalent ranking, and convert cosine cut-offs before thresholding scores.
  • Standard endpoints: tens of milliseconds, high QPS via target_qps, capacity that shrinks as dimension grows. Storage-optimized: a billion-plus vectors, cheaper, a few hundred milliseconds, triggered sync only, no columns_to_sync.
  • Cut cost by consolidating idle endpoints and using triggered sync; cut latency with service principal OAuth, smaller num_results, an always-on embedding endpoint and a separate query embedding endpoint serving the same model.
  • A non-owner needs USE CATALOG, USE SCHEMA and SELECT on the index to query it.

Frequently asked questions

What is the difference between a Delta Sync index and a Direct Vector Access index in Databricks Vector Search?

A Delta Sync index is built from a Unity Catalog Delta table and stays current by syncing from it, either when sync() is called (triggered) or continuously. It can have Databricks compute the embeddings from a text column or use vectors already stored in the table. A Direct Vector Access index has no source table: the application writes vectors into it with upsert calls and removes them with delete calls, and it always stores vectors the caller supplies.

When should I use a storage-optimized Vector Search endpoint instead of a standard endpoint?

Use a storage-optimized endpoint when the index is very large (hundreds of millions to billions of vectors) or cost per vector matters more than speed, and the application can accept a few hundred milliseconds of retrieval latency at modest query rates. Use a standard endpoint when retrieval must take tens of milliseconds, when throughput must scale with target_qps, or when you need continuous sync or columns_to_sync, which storage-optimized endpoints do not support.

Why doesn't my triggered Vector Search index show rows I just added to the Delta table?

A Delta Sync index in triggered mode does not watch its source table. It only updates when sync() is called through the SDK or REST API, or when Sync now is pressed in the UI. Add a sync() call as the last step of the job that writes the table, or use continuous sync if edits must appear within seconds and the extra always-on cost is acceptable.

Should I pass query_text or query_vector to similarity_search?

Pass query_text only to an index with Databricks-computed embeddings, because that index knows which embedding model to apply. For an index with self-managed embeddings or a Direct Vector Access index, embed the question yourself with the same model that produced the stored vectors and pass query_vector. Hybrid search on a self-managed index needs both: query_text for keyword matching and query_vector for vector similarity.

How does Databricks Vector Search compute similarity scores?

Vector Search uses HNSW approximate nearest-neighbor search with L2 (Euclidean) distance and returns a score of 1 divided by (1 plus the squared distance). If you normalize all stored and query vectors to unit length, ranking by this score matches ranking by cosine similarity, but the score value is not the cosine: for unit vectors a cosine of 0.7 corresponds to a score of 0.625.

How do I reduce the cost of Mosaic AI Vector Search?

Endpoints that host indexes bill for serving even when idle and do not scale to zero, so consolidate small, rarely used indexes onto one endpoint (each holds up to 50) and delete the empty ones. Use triggered sync instead of continuous sync when the source table changes on a schedule, and host large indexes that tolerate a few hundred milliseconds of latency on storage-optimized endpoints, which cost less per vector.

What permissions does a service principal need to query a Vector Search index?

If the service principal does not own the index, it needs USE CATALOG on the catalog, USE SCHEMA on the schema and SELECT on the index itself. SELECT on the source table is not enough, and endpoint permissions such as CAN USE control creating indexes on the endpoint rather than reading an index.

Can I query a Vector Search index from SQL?

Yes. The vector_search() table-valued function (Public Preview) runs on serverless or pro SQL warehouses and takes named arguments such as index, query_text or query_vector, num_results and query_type (ANN or HYBRID). It returns at most 100 results with no paging and does not support Direct Vector Access indexes; use similarity_search in Python for larger result sets.

Source

This lesson covers the "Assembling and Deploying Applications" domain of the official Databricks GenAI exam guide. Vendors revise their guides — check the source for the current version.

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?