OriginChain docs

Schema for Vector.

schema · 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"] }'