Graph queries
Graph queries walk relationships between rows. Examples: "all customers a supplier sells to", "friends of friends", "shortest path from order to fulfillment center". You declare which columns are relationships on the schema, then the graph endpoints walk them.
Edges are not stored separately - they're a view over your existing row columns. Writing a row creates / updates / removes the edges automatically. See Schemas → relations for the declaration.
1. Declare a relation.
Add a [[relations]] block to the schema of the table that holds the foreign-key column. After registering this schema, every row write creates the edges automatically.
# manifest.toml - declare the relation on the table holding the FK column.
# The reverse edge is written atomically when bidirectional = true.
namespace = "social"
table = "follows"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "follower_id"
ty = "str"
required = true
[[columns]]
name = "followee_id"
ty = "str"
required = true
[[relations]]
name = "followee" # the verb you walk in queries
from_col = "followee_id" # column on THIS table
bidirectional = true
[relations.target]
namespace = "social"
table = "users"
pk = "id" Self-relations work - direction tags in the key prevent collisions. See Schemas → relations for the full reference.
2. One-hop neighbors.
Return the primary keys of every row directly connected to a given row through a relation. The fastest graph query - just an adjacency list lookup.
curl "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.follows/neighbors?rel=followee&pk=u001" \
-H "Authorization: Bearer $OC_TOKEN"neighbors = db.graph.neighbors(
"social.follows",
rel="followee",
pk="u001",
)
for n in neighbors:
print(n.pk)const neighbors = await db.graph.neighbors("social.follows", {
rel: "followee",
pk: "u001",
});neighbors, err := db.Graph().Neighbors(ctx, "social.follows", originchain.NeighborsRequest{
Rel: "followee",
PK: "u001",
})
For inbound edges (who points at this row?), use the parallel /reverse endpoint with the same params.
3. BFS - multi-hop traversal.
Walk every node reachable within max_depth hops, breadth-first. Each result carries the hop distance.
curl "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.follows/bfs?rel=followee&pk=u001&max_depth=3" \
-H "Authorization: Bearer $OC_TOKEN"hits = db.graph.bfs(
"social.follows",
rel="followee",
pk="u001",
max_depth=3,
)
for h in hits:
print(h.pk, h.depth)const hits = await db.graph.bfs("social.follows", {
rel: "followee",
pk: "u001",
max_depth: 3,
});hits, err := db.Graph().BFS(ctx, "social.follows", originchain.BFSRequest{
Rel: "followee",
PK: "u001",
MaxDepth: 3,
}) - Forgetting max_depth. On a connected graph, BFS without a depth cap can return millions of nodes. Set
max_depthto the smallest value that gives you what you need. - Using BFS when you just want reachability. If you only need to know whether two nodes are connected, use
/path- it short-circuits on first match.
4. Shortest path (Dijkstra).
Find the lowest-cost path from src to dst. You provide a map of edge weights; the engine returns the total cost (or null if unreachable).
# weights_json maps "from→to" → cost. Empty {} = every edge weight 1.
curl "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.follows/dijkstra?rel=followee&src=u001&dst=u042&weights_json=%7B%7D" \
-H "Authorization: Bearer $OC_TOKEN"result = db.graph.dijkstra(
"social.follows",
rel="followee",
src="u001",
dst="u042",
weights={}, # default weight 1 per edge
)
print(result.cost) # None if unreachableconst result = await db.graph.dijkstra("social.follows", {
rel: "followee",
src: "u001",
dst: "u042",
weights: {},
});
console.log(result.cost); // null if unreachableresult, err := db.Graph().Dijkstra(ctx, "social.follows", originchain.DijkstraRequest{
Rel: "followee",
Src: "u001",
Dst: "u042",
Weights: map[string]float64{},
})
For top-K paths instead of the single shortest, use /k-shortest (Yen's algorithm). For unweighted shortest path, use /path.
5. All 19 algorithms.
Every graph endpoint, its wire shape, and what it's good for. Centrality and community algorithms (betweenness, eigenvector, label-propagation, triangles, louvain) require same-schema relations - cross-schema is not yet supported.
| operation | signature | use |
|---|---|---|
| neighbors | GET /graph/:schema/neighbors?rel=&pk= | One-hop forward - downstream of a node. |
| reverse | GET /graph/:schema/reverse?rel=&pk= | One-hop inbound - who points TO this node? |
| bfs | GET /graph/:schema/bfs?rel=&pk=&max_depth= | Breadth-first frontier up to a depth. |
| path | GET /graph/:schema/path?rel=&src=&dst=&max_depth= | Reachability check - short-circuits on first match. |
| all_simple_paths | GET /graph/:schema/all_simple_paths?rel=&src=&dst=&max_depth= | Every node-disjoint path. Hard-capped output. |
| dijkstra | GET /graph/:schema/dijkstra?rel=&src=&dst=&weights_json= | Weighted shortest path. |
| k-shortest | GET /graph/:schema/k-shortest?rel=&source=&target=&k= | Top-K loop-free paths in increasing weight. |
| pagerank | GET /graph/:schema/pagerank?rel=&nodes= | Influence ranking via power iteration. |
| triangles | GET /graph/:schema/triangles?rel=&nodes= | Per-node triangle count. Clustering signal. |
| components | GET /graph/:schema/components?rel=&nodes= | Connected components via Union-Find. |
| louvain | GET /graph/:schema/louvain?rel=&nodes= | Modularity-greedy community detection. |
| betweenness | GET /graph/:schema/betweenness?rel=&nodes= | Brandes' betweenness - bridge identification. |
| eigenvector_centrality | GET /graph/:schema/eigenvector_centrality?rel=&nodes= | Influence by who-you're-connected-to. |
| label_propagation | GET /graph/:schema/label_propagation?rel=&nodes= | Fast soft community detection. |
| random-walk | GET /graph/:schema/random-walk?rel=&pk=&steps=&seed= | Uniform or Node2Vec-biased walks. |
| node2vec | POST /graph/:schema/node2vec { rel, dim, ..., persist } | Train graph embeddings. |
| node2vec/topk | GET /graph/:schema/node2vec/:rel/topk?pk=&k= | Find similar nodes via Node2Vec embeddings. |
| graphsage | POST /graph/:schema/graphsage { rel, dim, ..., feature_col, persist } | Attribute-aware embeddings (Hamilton 2017). |
| graphsage/topk | GET /graph/:schema/graphsage/:rel/topk?pk=&k= | Find similar nodes via GraphSAGE. |