Vectors, geo and RAG search

Index a collection's vector, geo or sparse fields, then query them with k-nearest, bounding-box and RAG search operators.

Docs menu
{"where": {"embedding": {"$knn": {"vector": [0.1, 0.2, 0.3], "k": 10}}}}

Indexing a vector field

Declare a vector index before querying it, with index.create (kind: "vector", POST /v1/_indexes):

Field Type Default Description
collection string required The collection
field string required The vector field
dims integer required (17-4096) The vectors' dimensions, fixed once set
metric string l2 l2 (squared Euclidean) or cosine
bands array of 3 integers chosen by dims Dims coded at 3, 2 and 1 levels
route integer 128 (at most dims) Dims the index routes clusters on
clusters integer grows with the vectors A fixed cluster count
curl -s -X POST $SUBSTRIO_URL/v1/_indexes -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' \
  -d '{"kind":"vector","collection":"docs","field":"embedding","dims":384,"metric":"cosine"}'

A vector of other dimensions is refused once the index is set.

Vector queries

{"where": {"embedding": {"$knn": {"vector": [0.1, 0.2, 0.3], "k": 10}}}}
{"where": {"embedding": {"$box": {"min": [0.0, 0.0, 0.0], "max": [1.0, 1.0, 1.0]}}}}

$knn answers the k nearest vectors to vector (default k 10) by the field's configured metric. $box matches vectors inside the per-dimension min/max bounds. For a sparse vector field, $sparseKnn takes the same k, with vector as {"indices": [...], "values": [...]}.

Geo queries

{"where": {"location": {"$near": {"lat": 40.7128, "lng": -74.0060, "k": 10}}}}
{"where": {"location": {"$geoWithin": {"$sphere": {"center": {"lat": 40.7128, "lng": -74.0060}, "radius": 5000}}}}}

$near answers the k nearest documents to a lat/lng point. $geoWithin with $box (sw/ne corners) or $sphere (center and radius in meters) matches points inside a region. See query-language.md for the full operator set.

RAG configuration

rag.collection.set (PUT /v1/{collection}/_rag) declares how a collection embeds and searches:

Field Type Default Description
source_field string required The text field to embed
provider.type string required openai, anthropic, ollama, groq, vllm, jina or hash
provider.model string provider default The embedding model
provider.endpoint string provider default Override the provider's URL
provider.api_key_ref string none A secret reference holding the API key
provider.dimensions integer provider default Embedding size
vector_field string source_field + _vector Where the embedding is stored
search_mode string vector vector, sparse or hybrid
auto_chunk boolean false Split long text before embedding
chunk_size, chunk_overlap integer provider default Chunk sizing when auto_chunk is on

hash is a deterministic embedding with no semantic meaning: useful for repeatable tests, not for production relevance.

curl -s -X PUT $SUBSTRIO_URL/v1/docs/_rag -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' \
  -d '{"source_field":"body","provider":{"type":"openai","model":"text-embedding-3-small"}}'

rag.collection.get (GET /v1/{collection}/_rag) reads the configuration back; rag.collection.delete (DELETE /v1/{collection}/_rag) removes it; rag.get (GET /v1/_rag) reads the app's own configuration. rag.embed (POST /v1/{collection}/_rag/embed) embeds records that have no vector yet; rag.reembed (POST /v1/{collection}/_rag/re-embed) embeds every record again, for a changed provider or model. rag.drift (GET /v1/{collection}/_rag/drift) reports records whose stored embedding no longer matches the current configuration.

$search runs vector, sparse and text search together and fuses the results, scoped to the field rag.collection.set configured:

{"$search": {"query": "refund policy", "mode": "hybrid", "k": 20}}
Field Type Default Description
query string required The search text
mode string vector vector/dense (embedding only), sparse (sparse-only), anything else (hybrid: dense, sparse and text fused)
k integer 50 Candidates considered before limit/skip apply
decay object none Scores recent documents higher by a configured field
strict_model boolean false Only match vectors from the current embedding model
boost_feedback boolean or object false Re-rank using recorded search feedback

$search can take a bare string ({"$search": "refund policy"}) in place of the object form, and composes with a regular where clause.

ai.cross_search (POST /v1/{collection}/_cross_search) runs one query across several vector fields of the same collection and merges the results, k candidates per field:

curl -s -X POST $SUBSTRIO_URL/v1/docs/_cross_search -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' \
  -d '{"query":"refund policy","fields":["title_vector","body_vector"],"k":10}'

search.analytics (GET /v1/{collection}/_analytics/search) reads query volume and result counts for a collection's search traffic.