Schema for Graph algorithms.
OriginChain ships 19 graph algorithms — neighbors, reverse, BFS, path, all_simple_paths, Dijkstra, k-shortest, PageRank, triangles, components, Louvain, betweenness, eigenvector_centrality, label_propagation, random-walk, Node2Vec (POST + topk), GraphSAGE (POST + topk). Every one operates on a [[relations]] block declared in the schema TOML.
Engine surface: GET /v1/tenants/:t/graph/:schema/<algo>?rel=<name>&… for read algos. POST /…/node2vec | /graphsage for training. GET /…/node2vec/:rel/topk | /graphsage/:rel/topk for persisted-embedding similarity.
Required schema fields.
Without these, this query surface doesn't function at all.
| field | effect |
|---|---|
| namespace + table + primary_key + [[columns]] | Standard table requirements — algorithms operate on rows in this schema. |
| [[relations]] with name + from_col | The rel= query param on every graph endpoint maps to this name. Without a declared relation, no algorithm runs. |
| [relations.target] sub-table | Algorithms resolve target rows by PK via this descriptor (namespace + table + pk). |
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 |
|---|---|---|---|
| [[relations]] bidirectional | bool | true | Required for /reverse, /bfs from target, and any algorithm that traverses against edge direction. |
| Multiple [[relations]] blocks | — | — | Each new relation is a new verb in the URL ?rel= param. Same-schema relations unlock the 6 same-schema-only algorithms (triangles, components, louvain, betweenness, eigenvector_centrality, label_propagation). |
Which algorithms work on which relation shape.
- Cross-schema (orders → products): 13 algorithms — neighbors, reverse, bfs, path, all_simple_paths, dijkstra, k-shortest, pagerank, random-walk, node2vec, node2vec/topk, graphsage, graphsage/topk
- Same-schema (users → users): all 19 algorithms, including triangles, components, louvain, betweenness, eigenvector_centrality, label_propagation
Algorithm limits.
The engine returns a typed 400 with a hint instead of running these. Knowing them up front avoids a debugging round-trip.
| shape | why |
|---|---|
| triangles / components / louvain / betweenness / eigenvector_centrality / label_propagation on a CROSS-schema relation | Engine returns 400 cross-schema not in v1. Workaround: model the edge as a same-schema relation (e.g. user → user) or compute these client-side. |
| all_simple_paths_bidir without bidirectional=true | Engine returns 400 bidirectional traversal requires bidirectional = true. Either flip the flag or use /all_simple_paths. |
Abbreviation legend.
| token | meaning |
|---|---|
| rel= | URL query param on every /graph/... endpoint — maps to the [[relations]] name field |
| pk= | URL query param for the seed node — value is a row's primary key (e.g. o001) |
| src= / dst= | Source / destination PKs for path / dijkstra / all_simple_paths endpoints |
| source= / target= | Same as src/dst but for /k-shortest (different param names — engine specific) |
| nodes= | Comma-separated seed PK list for pagerank, triangles, components, louvain, etc |
| max_depth= | BFS / path depth cap. Higher = larger frontier |
| nprobe= / damping= / max_iter= / tol= | Algorithm-specific tuning knobs (PageRank, etc) |
| persist= | POST body field on node2vec / graphsage — true persists embeddings so /topk works |
Worked example.
Schema TOML — copy + register via POST /v1/tenants/:t/schemas with Content-Type: text/plain.
# Bipartite shape — orders → products
namespace = "shop"
table = "orders"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "customer_id"
ty = "str"
required = true
[[columns]]
name = "product_id"
ty = "str"
required = true
[[relations]]
name = "bought_product"
from_col = "product_id"
bidirectional = true
[relations.target]
namespace = "shop"
table = "products"
pk = "id"
# Same-schema shape — users → users (unlocks community + centrality algos)
# Declared on a separate table social.follows
[[relations]]
name = "follower"
from_col = "follower_id"
bidirectional = true
[relations.target]
namespace = "social"
table = "users"
pk = "id" Queries it enables.
# Single-hop adjacency
curl "$BASE/v1/tenants/$T/graph/shop.orders/neighbors?rel=bought_product&pk=o001" \
-H "Authorization: Bearer $BEARER"
# BFS frontier (depth 3)
curl "$BASE/v1/tenants/$T/graph/shop.orders/bfs?rel=bought_product&pk=o001&max_depth=3" \
-H "Authorization: Bearer $BEARER"
# Reverse — who bought p001? (works because bidirectional=true)
curl "$BASE/v1/tenants/$T/graph/shop.orders/reverse?rel=bought_product&pk=p001" \
-H "Authorization: Bearer $BEARER"
# Dijkstra (default weight 1.0 — pass weights_json={} for unweighted)
curl "$BASE/v1/tenants/$T/graph/shop.orders/dijkstra?rel=bought_product&src=o001&dst=p001&weights_json=%7B%7D" \
-H "Authorization: Bearer $BEARER"
# K-shortest (uses source/target — different param names)
curl "$BASE/v1/tenants/$T/graph/shop.orders/k-shortest?rel=bought_product&source=o001&target=p001&k=3" \
-H "Authorization: Bearer $BEARER"
# PageRank over a seed set
curl "$BASE/v1/tenants/$T/graph/shop.orders/pagerank?rel=bought_product&nodes=o001,o002,o003,o004,o005" \
-H "Authorization: Bearer $BEARER"
# Node2Vec — train + persist for similarity top-k
curl -X POST $BASE/v1/tenants/$T/graph/shop.orders/node2vec -H "Authorization: Bearer $BEARER" \
-d '{"rel":"bought_product","dim":16,"walks_per_node":4,"walk_length":6,"window":3,"epochs":1,"p":1.0,"q":1.0,"persist":true}'
curl "$BASE/v1/tenants/$T/graph/shop.orders/node2vec/bought_product/topk?pk=o001&k=5" \
-H "Authorization: Bearer $BEARER"