Graph models by industry
Four questions that are awkward in rows and natural as a traversal: a fraud ring, a two-hop product recommendation, a supply-chain blast radius and an org chart. Each starts with the relation, because declaring which column is an edge is the whole setup.
Financial services: finding a fraud ring
Individually ordinary accounts, connected in a way that is not. The signal is the shape, not any single row.
The relation
fin.transfers (id PK, from_account, to_account, amount_minor, at)
relation: "to_account" -> fin.accountsWho is within three hops of a flagged account
A ring shows up as a small set reachable in a few hops and reaching back. One traversal replaces a recursive query you would otherwise write by hand.
GET /v1/tenants/:t/graph/fin.transfers/bfs
?rel=to_account&from=acct-flagged&depth=3A traversal returns the path, not just the endpoint, so an investigator can see WHY an account was surfaced. That matters more than the score when a decision has to be justified.
Retail: people who bought this also bought
The classic two-hop recommendation, computed on live orders rather than a nightly export.
The relation
shop.lines (id PK, order_id, product_id, qty)
relation: "product_id" -> shop.productsTwo hops from a product
Product to the orders containing it, then out to the other products in those orders. Depth two, one call.
GET /v1/tenants/:t/graph/shop.lines/bfs
?rel=product_id&from=sku-8842&depth=2Then rank them by similarity
Traversal gives candidates; vector search orders them by how alike they actually are. The two surfaces read the same rows — see the vector quickstart.
POST /v1/tenants/:t/vector/shop.products/topkManufacturing: a supply-chain dependency
One supplier stops shipping. The question is what stops with it, several levels down.
The relation
mfg.bom (id PK, part_id, depends_on_part, qty)
relation: "depends_on_part" -> mfg.partsEverything downstream of a part
Blast radius is a traversal, and the depth is the answer to how far the problem travels.
GET /v1/tenants/:t/graph/mfg.bom/bfs
?rel=depends_on_part&from=part-4471&depth=5Give the edge a cost - lead time, price, distance - and Dijkstra answers the cheapest path rather than the shortest hop count.
Enterprise: an org chart
Reporting lines are a graph that everyone models as rows and then queries badly.
The relation
hr.people (id PK, name, manager_id, dept)
relation: "manager_id" -> hr.peopleEveryone under a manager
A self-referencing relation traverses the same way as any other.
GET /v1/tenants/:t/graph/hr.people/bfs
?rel=manager_id&from=p-17&depth=6What these have in common
- The relation is the model. Declaring which column is an edge is the whole setup.
- No second database. Edges are columns on rows you already write, so there is nothing to sync and nothing to fall behind.
- Paths, not just answers. A traversal returns how it got there, which is what makes the result defensible.