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","weight":1.0,"graph":"social", ...}
graph meta reports the counts:
strata graph meta social
{"graph":"social","node_count":4,"edge_count":3, ...}
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
{"depths":{"alice":0,"bob":1,"carol":2}, "edges":[...]}
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
reports a component per node and a count, which is the quickest way to find out
whether your graph is one thing or several:
{"component_count":2,"components":{"alice":"alice","bob":"alice", ...}}
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 graph takes its contents with it, without asking.
strata graph delete social on a populated graph succeeds immediately. Compare
space delete, which refuses when a space still holds data and makes you pass
--force. Tracked as strata-core issue 3122.
Where to look next
Every graph command, with its parameters, return shape and error codes, is in the graph reference.