Vector search
Vector search adds semantic retrieval to a collection: configure which field holds the embedding and where its text comes from, and Groveback embeds documents on write and ranks them on query.
Configure a collection
Section titled “Configure a collection”curl -X PUT "$URL/api/v1/admin/collections/articles/vector-config" \ -H "authorization: Bearer $ADMIN_KEY" -H 'content-type: application/json' \ -d '{ "fields": [{ "field": "embedding", "dimensions": 384, "similarity": "cosine", "source": "body", "mode": "byo", "provider": "local", "filterFields": ["status", "tenantId"] }] }'| Key | Meaning |
|---|---|
field |
The logical name of the vector field. |
dimensions |
1–4096. Must match the provider’s model. |
similarity |
cosine, euclidean or dotProduct. |
source |
The document field whose text gets embedded. |
mode |
byo or auto-embed — see below. |
provider / model |
Which embedder to use. |
filterFields |
Fields indexed for exact pre-filtering during search. |
In the bundle this lives at groveback/vectors/<collection>.json, keyed by collection.
Two modes
Section titled “Two modes”mode: "byo" — Groveback embeds your source field through a provider and stores the
vector itself. Works with any backend.
mode: "auto-embed" — MongoDB does the embedding natively (the provider is a native
model id) and the search reads the source field directly. Requires a MongoDB deployment that
supports it.
Providers
Section titled “Providers”| Provider | Notes |
|---|---|
mock |
Deterministic and offline — hash-based, not semantic. Only identical-text ranking is meaningful. For tests. |
local |
An OpenAI-compatible endpoint or HuggingFace TEI, via EMBEDDINGS_URL. |
openai |
Needs OPENAI_API_KEY. |
voyage |
Needs VOYAGE_API_KEY. |
make dev-vector brings up the full local stack including a TEI embeddings service.
Embedding is automatic and best-effort
Section titled “Embedding is automatic and best-effort”On a write, a subscriber embeds the source field and stores the vector at __vec_<field>
plus a hash of the source at __vec_<field>_hash. The hash is the loop guard — an unchanged
source is not re-embedded.
Skipped silently when there is no provider, the source is empty, or the source is not a string. At most four embeds are in flight at once; excess events are dropped.
Querying
Section titled “Querying”curl -X POST "$URL/api/v1/articles/search" \ -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \ -d '{"text":"how do policies work","limit":5,"filter":{"status":"published"}, "fields":["title","url"]}'const hits = await client.collection('articles').search({ text: 'how do policies work', limit: 5,});// each hit carries _score| Field | Meaning |
|---|---|
text |
Embedded server-side. Auto-embed backends require this and reject a precomputed vector. |
vector |
A precomputed embedding. |
limit |
Result count. |
filter |
A Mongo-style pre-filter, on top of the policy filter. |
fields |
Inclusion projection; id and _score are always returned. |
field |
Which vector field to search when several are configured. Defaults to the first. |
Naming an unknown vector field is an explicit validation error, not a silent fallback to the default.
Authorization
Section titled “Authorization”Search is authorized by the list rule, and the policy filter post-filters the
candidates. It is scoped as a read operation, so a read-scoped API key can run it.
Because projection is applied last, a fields list can only ever narrow what you are already
allowed to see.
GraphQL
Section titled “GraphQL”Two entry points: the generic vectorSearch field, and a typed <collection>_search field on
every collection with a vector config.
query { articles_search(text: "policies", limit: 5) { id title }}Plan limits
Section titled “Plan limits”On hosted deployments a vectors gauge counts stored BYO embeddings. At quota, new
embeddings are skipped while the document write itself proceeds untouched; re-embeds always go
through, so an edit never breaks. auto-embed fields are not metered.
In-memory caveat
Section titled “In-memory caveat”Under grove dev without --mongo, vector search works only with a supplied query
vector — embedding text at query time needs MongoDB. Point at a real Mongo for full
behavior:
grove dev --mongo mongodb://localhost:27017/dev