Graph

Graph is for data where the relationships are the thing you query. Use it when you want to ask who is connected to whom, what depends on what, or how far apart two things are, and when answering that with joins would mean joining a table to itself an unknown number of times.

strata graph create social
strata graph add-node social alice
strata graph add-node social bob
strata graph add-edge social alice knows bob

Note the edge argument order: graph, source, type, destination. It reads as a sentence, alice knows bob, and getting it wrong is the easiest mistake to make here because every argument is a bare string.

Nodes, edges and what they carry

Both take properties, and an edge carries a weight that defaults to 1:

strata graph add-node social alice --properties '{"age":30}'
strata graph get-edge social alice knows bob
src        alice
edge_type  knows
dst        bob
graph      social
weight     1.0
version    9

graph meta reports the counts:

strata graph meta social
graph            social
node_count       5
edge_count       3
created_version  3
updated_version  11

Walking the graph

neighbors is the one-hop question, and it returns the edge and the node together with the direction it was traversed, so you do not need a second read to find out why a node came back.

strata graph neighbors social alice

For more than one hop there is a bounded breadth-first traversal:

strata graph bfs social alice
NODE   DEPTH
alice      0
bob        1
carol      2

Depths come back keyed by node, which is usually what you wanted rather than the path itself.

Analytics

Five whole-graph algorithms ship as commands rather than as something you implement on top of reads:

strata graph wcc social
strata graph pagerank social
strata graph sssp social alice
strata graph lcc social
strata graph cdlp social

Weakly connected components, PageRank, single-source shortest paths, local clustering coefficients, and community detection by label propagation. wcc names the component each node belongs to, which is the quickest way to find out whether your graph is one thing or several. Two component names here, so two islands:

NODE   COMPONENT
alice  alice
bob    alice
carol  alice
dave   dave
erin   dave

The count itself is in --json as component_count, not in the table.

The ontology is optional until you freeze it

This is the part worth understanding, because it is unusual and it is the reason graph here is not just a table of edges.

A graph starts with a draft ontology. You can declare object and link types, and you can also ignore them entirely: while the ontology is a draft, a node may declare a type nobody defined.

strata graph ontology define-object-type kb person
strata graph add-node kb alice --type person
strata graph add-node kb ghost --type alien

Both writes succeed, including the one using an undeclared type. Then you freeze:

strata graph ontology freeze kb
strata graph add-node kb bob --type alien
failed_precondition.engine.graph_ontology_node_type: node object type ...

After the freeze, writes validate against the declared types. So the shape is explore first, commit later: leave it loose while you are still learning what your data looks like, and freeze once you know.

Three things about freezing are worth knowing before you do it.

It is one way. Defining a new type afterwards fails with failed_precondition.engine.graph_ontology_frozen.

It is not retroactive. ghost, written with an undeclared type before the freeze, is still there and still readable afterwards. Freezing constrains what happens next, it does not audit what already happened.

And the ontology only knows about declared types, so strata graph ontology summary kb counts nodes per declared type and does not mention ghost at all. If you froze a graph that already had loose data in it, the summary understates what is actually stored.

Sharp edges

Names differ between the CLI and the catalog. The CLI uses compound verbs, add-node and get-edge, while the command catalog and the reference pages use nested names, graph.node.add and graph.edge.get. They are the same operations.

Three commands have no CLI form. bindings, batch_write and apply_delete_policy exist in the engine and are reachable from the SDK or the command escape hatch, but strata graph bindings is not a command. Their reference pages show the Python spelling and the wire type rather than an invocation that would not run.

Deleting a populated graph is refused until you say so. strata graph delete social on a graph that still holds nodes or edges fails with failed_precondition.engine.graph_not_empty and deletes nothing; pass --force to drop its contents along with it. This matches space delete, which has always refused while a space holds data. Graph delete asked for nothing before 1.2.5.

Where to look next

Every graph command, with its parameters, return shape and error codes, is in the graph reference.

Verified against strata-core@v1.2.7 · Edit this page · Report an issue

agents: this page as markdown → /docs/learn/graph.md