MongoDB Vector Search — Python and Atlas Modes¶
MongoVectorBackend exposes two vector-search modes:
| Mode | Switch | When to use |
|---|---|---|
| Python (default) | vector_search_mode="python" (or omit) |
Development, demos, small corpora (~ < 100K vectors per tenant). Cosine similarity computed in application code over every tenant vector. |
| Atlas | vector_search_mode="atlas" |
Production. Server-side approximate-nearest-neighbour search via MongoDB Atlas's $vectorSearch aggregation stage. Scales sublinearly. |
The default python mode is byte-identical to v7.20.0 behaviour. Existing adopters
keep their code unchanged on upgrade.
Python mode¶
The constructor's defaults pick the Python mode:
from symfonic.memory.backends.mongodb import MongoVectorBackend
backend = MongoVectorBackend(uri="mongodb://localhost:27017")
# Default: vector_search_mode="python"
backend.search(scope, query_embedding, top_k=5) fetches every vector matching
{"tenant_id": scope.tenant_id}, computes cosine similarity in Python, sorts,
and returns the top k. Tenant isolation is enforced by the {"tenant_id": ...}
filter on the find() call.
Cost profile. Linear in the per-tenant corpus size. A 1M-vector tenant incurs 1M cosine evaluations per query. Acceptable for development. Painful in production once a tenant's corpus crosses ~100K vectors.
Atlas mode¶
from symfonic.memory.backends.mongodb import MongoVectorBackend
backend = MongoVectorBackend(
uri="mongodb+srv://...mongodb.net/",
vector_search_mode="atlas",
atlas_index_name="symfonic_vector_idx",
atlas_num_candidates_multiplier=10, # default
atlas_num_candidates_min=100, # default
)
backend.search(...) issues an aggregation pipeline that pushes the ANN search
to the Atlas server. The pipeline has three stages — every stage is
load-bearing for tenant isolation. See
Guide 15 — MongoDB Atlas Vector Search
for the full set-up, including the load-bearing $match defence-in-depth nuance.
Atlas-mode parameters¶
| Parameter | Default | Purpose |
|---|---|---|
vector_search_mode |
"python" |
Set to "atlas" to enable. Unknown values raise ValueError at boot. |
atlas_index_name |
"vector_index" |
Name of the Atlas vector-search index. Must exist on the collection or be created via ensure_vector_search_index(). |
atlas_num_candidates_multiplier |
10 |
Multiplied by top_k to compute Atlas's numCandidates. Higher values trade query latency for recall. |
atlas_num_candidates_min |
100 |
Floor for numCandidates so small top_k values still query enough candidates to surface relevant hits. |
numCandidates is computed as max(min, multiplier × top_k). For top_k=5 with
defaults, Atlas considers at least 100 candidates; for top_k=100, it
considers 1000. Atlas's docs recommend numCandidates >= 10 × limit for good
recall on production-sized corpora.
Bootstrapping the Atlas index¶
Idempotent — safe to call on every boot. Reads list_search_indexes() and
short-circuits if atlas_index_name already exists. When the index is missing,
the helper creates it with two field definitions:
- A
vectorfield onembeddingcarrying the embedding dimension and similarity function. - A
filterfield ontenant_id.
The filter field is what enables the $vectorSearch.filter clause inside
_search_atlas to actually pre-filter at the index level. Without it, the
filter clause is a silent no-op — see the load-bearing-$match note in
Guide 15.
Migration path¶
- Dev / staging. Keep
vector_search_mode="python". No changes needed. - Add Atlas index. Provision a MongoDB Atlas cluster (M10 or higher
supports Vector Search). Either run
ensure_vector_search_indexfrom your boot script or create the index in the Atlas UI per Guide 15. - Switch the flag. Set
vector_search_mode="atlas"in your backend construction. Restart. Samebackend.search(...)calls now run server-side. - Tune
num_candidates. Watch query latency vs recall. If latency tolerable but quality low, raiseatlas_num_candidates_multiplier.
The switch is observable. Cache prefixes computed from search results stay
stable as long as the embedding model and corpus are unchanged. Adopters that
require byte-identical scores across modes should leave the mode at python;
Atlas's ANN scoring is approximate by construction.