OriginChainDB docs
graph · by industry

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.accounts

Who 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=3
keep it explainable

A 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.products

Two 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=2

Then 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/topk

Manufacturing: 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.parts

Everything 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=5
weights make it a route

Give 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.people

Everyone 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=6

What 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.