Schema for Vector.
Vector indexes are NOT declared in the schema TOML. Every dim / metric / index-kind decision lives on the runtime POST endpoints. The :table on the URL is a free-text bucket — does not have to match a registered schema.
Engine surface: 9 endpoint families under /v1/tenants/:t/vector/:table/... — put, put_bulk, put_sparse, topk, topk_sparse, topk_hybrid, install-centroids, train-and-install-centroids, centroids, ivf-rebalance-status, delete, delete-bulk.
Required schema fields.
Without these, this query surface doesn't function at all.
| field | effect |
|---|---|
| (none) | Vector indexes live entirely at runtime. The :table on the URL is a logical bucket — does NOT need to be a registered schema. |
Optional fields — what each one unlocks.
Add only the fields whose effect you need. Each one buys a specific capability — speed up a predicate, guard a write, or unlock a new query shape.
| field | type | default | effect |
|---|---|---|---|
| dim (per put request) | int | — | Dimensionality. Locked at the table's first put — subsequent dim mismatch returns 400. |
| metric (per put / topk) | string | cosine | cosine | dot | l2 | manhattan (alias l1). Set on each call. |
| index (per put / topk) | string | hnsw | hnsw (default) | ivf (needs centroids installed first) | ivf_pq (compressed at scale). |
| quantization (per put) | string | none | none (default) | scalar (~4× smaller on disk, ~1% recall loss). |
| metadata (per put) | object | {} | Per-vector key/value map. Indexed for equality post-filter at topk time. |
| mode (per topk) | string | high_recall | fast | high_recall — picks HNSW beam width. |
| filter (per topk) | object | {} | Metadata equality filter. Non-empty → HNSW + post-filter pipeline. |
| nprobe (per topk, IVF only) | int | min(8, partitions) | How many IVF cells the query visits. Required when index=ivf; higher → better recall, slower. |
What you can call (no schema knob needed).
- POST /vector/:table/put — single dense insert
- POST /vector/:table/put_bulk — bulk insert (up to VEC_PUT_BULK_MAX per call)
- POST /vector/:table/put_sparse — CSR-like sparse insert (SPLADE, uniCOIL)
- POST /vector/:table/topk — default HNSW or IVF with index=ivf
- POST /vector/:table/topk_sparse — sparse top-k
- POST /vector/:table/topk_hybrid — RRF fusion of dense + sparse in one round-trip
- POST /vector/:table/install-centroids — install pre-trained IVF cells
- POST /vector/:table/train-and-install-centroids — inline k-means
- GET /vector/:table/centroids — read installed centroids (truncated preview)
- GET /vector/:table/ivf-rebalance-status — read RebalanceAction (None | Recommended | Required)
- DELETE /vector/:table/:vec_id — single delete (idempotent)
- POST /vector/:table/delete-bulk — bulk delete up to MAX_BULK_DELETE = 10_000
Abbreviation legend.
| token | meaning |
|---|---|
| HNSW | Hierarchical Navigable Small World graph — default in-memory dense index |
| IVF | Inverted File — centroid + posting list. Sub-linear at >1M vectors |
| IVF-PQ | IVF + Product Quantization — compressed posting payload for ≥100M scale |
| PQ | Product Quantization — codebook compression |
| RRF | Reciprocal Rank Fusion — server-side dense + sparse score combination |
| dim | Dimensionality of the vector. Locked at first put per (tenant, table) |
| metric | Distance function — cosine | dot | l2 | manhattan (alias l1) |
| nprobe | How many IVF cells a query visits — recall ↔ latency knob |
| M / ef_construction | HNSW build params (M=16, ef_construction=200 by default) |
| fast / high_recall | HNSW query mode preset — narrower or wider beam width per call |
Worked example.
Schema TOML — copy + register via POST /v1/tenants/:t/schemas with Content-Type: text/plain.
# ──────────────────────────────────────────────────────────────────────
# Important: vector indexes are NOT declared in the schema TOML.
# The grammar oc_schema::Manifest accepts does NOT have a [[extractions.vector]]
# or "dim" / "metric" block. dim + metric + index + quantization all live
# on the runtime POST /vector/:table/put body — one per call.
#
# What the TOML IS for (vector workflows): registering the ROW schema so the
# same row is reachable via SQL alongside vector top-k. Same id used in the
# /vector URL keeps everything aligned.
# ──────────────────────────────────────────────────────────────────────
namespace = "shop"
table = "products"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "name"
ty = "str"
[[columns]]
name = "category"
ty = "str"
[[columns]]
name = "price_cents"
ty = "i64"
[[columns]]
name = "description"
ty = "str"
[[indexes]]
name = "by_category"
columns = ["category"] Runtime calls.
# ════════════════════════════════════════════════════════════════════
# INSERT — 5 flavours
# ════════════════════════════════════════════════════════════════════
# 1) Single dense vector — 8-dim, cosine, no metadata
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/put -H "Authorization: Bearer $BEARER" \
-H "Content-Type: application/json" \
-d '{
"id": "p001",
"embedding": [0.9070, 0.0907, 0.1186, 0.1119, 0.4997, 0.1839, 0.1011, 0.1135],
"dim": 8,
"metric": "cosine"
}'
# 2) Dense + metadata (so you can post-filter at topk time)
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/put -H "Authorization: Bearer $BEARER" \
-H "Content-Type: application/json" \
-d '{
"id": "p002",
"embedding": [0.911, 0.082, 0.123, 0.099, 0.502, 0.193, 0.105, 0.118],
"dim": 8,
"metric": "cosine",
"metadata": { "category": "electronics", "brand": "acme", "in_stock": true }
}'
# 3) Dense at OpenAI text-embedding-3-small scale (1536-dim)
curl -X POST $BASE/v1/tenants/$T/vector/docs/put -H "Authorization: Bearer $BEARER" \
-H "Content-Type: application/json" \
-d '{
"id": "doc_42",
"embedding": [/* 1536 floats from OpenAI */],
"dim": 1536,
"metric": "cosine",
"metadata": { "url": "https://example.com/post-42", "lang": "en" }
}'
# 4) Dense with scalar quantization — ~4× smaller on disk, ~1% recall loss
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/put -H "Authorization: Bearer $BEARER" \
-d '{
"id": "p003", "embedding": [/* 768 floats */], "dim": 768, "metric": "cosine",
"quantization": "scalar"
}'
# 5) Bulk dense (body-limit disabled — supports multi-GB ingest)
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/put_bulk -H "Authorization: Bearer $BEARER" \
-H "Content-Type: application/json" \
-d '{
"dim": 768,
"metric": "cosine",
"vectors": [
{ "id": "p001", "embedding": [/* 768 floats */], "metadata": { "category": "electronics" } },
{ "id": "p002", "embedding": [/* 768 floats */], "metadata": { "category": "electronics" } },
{ "id": "p003", "embedding": [/* 768 floats */], "metadata": { "category": "books" } }
]
}'
# 6) Sparse vector — for SPLADE / uniCOIL / one-hot category encodings
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/put_sparse -H "Authorization: Bearer $BEARER" \
-d '{
"id": "p001-lex",
"indices": [12, 84, 137, 920, 4051],
"values": [0.5, 0.3, 0.7, 0.2, 0.4],
"dim": 30000,
"metric": "l2"
}'
# ════════════════════════════════════════════════════════════════════
# TOP-K — 6 flavours
# ════════════════════════════════════════════════════════════════════
# 1) Default HNSW top-K (high_recall preset)
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk -H "Authorization: Bearer $BEARER" \
-d '{
"query": [0.9070, 0.0907, 0.1186, 0.1119, 0.4997, 0.1839, 0.1011, 0.1135],
"k": 5,
"dim": 8,
"metric": "cosine"
}'
# 2) Fast preset — narrower beam, lower latency, slight recall trade
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk -H "Authorization: Bearer $BEARER" \
-d '{
"query": [/* 768 floats */],
"k": 10,
"dim": 768,
"metric": "cosine",
"mode": "fast"
}'
# 3) Metadata-filtered — HNSW + post-filter on equality keys
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk -H "Authorization: Bearer $BEARER" \
-d '{
"query": [/* 768 floats */],
"k": 10,
"dim": 768,
"metric": "cosine",
"filter": { "category": "electronics", "in_stock": true }
}'
# 4) IVF top-K — sub-linear at >1M vectors. nprobe = cells visited.
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk -H "Authorization: Bearer $BEARER" \
-d '{
"query": [/* 768 floats */],
"k": 20,
"dim": 768,
"metric": "cosine",
"index": "ivf",
"nprobe": 16
}'
# 5) Sparse top-K
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk_sparse -H "Authorization: Bearer $BEARER" \
-d '{
"query_indices": [12, 84, 137, 920],
"query_values": [0.5, 0.3, 0.7, 0.2],
"k": 5,
"dim": 30000,
"metric": "l2"
}'
# 6) Hybrid dense + sparse with Reciprocal Rank Fusion server-side
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/topk_hybrid -H "Authorization: Bearer $BEARER" \
-d '{
"dense_query": [/* 768 floats */],
"dense_dim": 768,
"sparse_indices": [12, 84, 137],
"sparse_values": [0.5, 0.3, 0.7],
"sparse_dim": 30000,
"k": 10,
"metric": "cosine"
}'
# ════════════════════════════════════════════════════════════════════
# IVF centroid lifecycle (required before any IVF put or IVF topk)
# ════════════════════════════════════════════════════════════════════
# Install pre-trained centroids — one row per cell
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/install-centroids -H "Authorization: Bearer $BEARER" \
-d '{
"centroids": [
[0.9, 0.1, 0.1, 0.1, 0.5, 0.2, 0.1, 0.1],
[0.1, 0.9, 0.1, 0.1, 0.2, 0.5, 0.1, 0.1],
[0.1, 0.1, 0.9, 0.1, 0.1, 0.1, 0.5, 0.2],
[0.1, 0.1, 0.1, 0.9, 0.1, 0.1, 0.2, 0.5]
]
}'
# OR train inline via mini-batch k-means
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/train-and-install-centroids -H "Authorization: Bearer $BEARER" \
-d '{ "partitions": 1024, "iters": 25 }'
# Read installed centroids (truncated preview)
curl $BASE/v1/tenants/$T/vector/shop_products/centroids -H "Authorization: Bearer $BEARER"
# Read IVF rebalance status (None | Recommended | Required)
curl $BASE/v1/tenants/$T/vector/shop_products/ivf-rebalance-status -H "Authorization: Bearer $BEARER"
# ════════════════════════════════════════════════════════════════════
# Delete — single + bulk
# ════════════════════════════════════════════════════════════════════
# Single (idempotent — returns {deleted: false} if missing)
curl -X DELETE $BASE/v1/tenants/$T/vector/shop_products/p001 -H "Authorization: Bearer $BEARER"
# Bulk — up to MAX_BULK_DELETE = 10_000 ids per call
curl -X POST $BASE/v1/tenants/$T/vector/shop_products/delete-bulk -H "Authorization: Bearer $BEARER" \
-d '{ "ids": ["p001", "p002", "p003"] }'