Graph storage and analytics

Store directed edges between integer node ids under a label, then read neighbors, degree and run graph analytics over them.

Docs menu
curl -s -X POST $SUBSTRIO_URL/v1/_graph/follows/edges -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' -d '{"src":1,"dst":2}'
# {"label":"follows","src":1,"dst":2,"added":true}

A graph label is a set of directed edges between node ids (plain integers, not documents). A label is created the first time an edge is written to it.

Edges

Operation Route Scope
graph.label.list GET /v1/_graph read-only
graph.edge.read GET /v1/_graph/{label}/edges or POST .../edges/_check read-only
graph.edge.write POST /v1/_graph/{label}/edges curator
graph.edge.remove POST /v1/_graph/{label}/edges/_remove curator

Each edge call takes {"src": <integer>, "dst": <integer>} and answers {"label", "src", "dst", "exists"|"added"|"removed"}. Writing an edge that already exists, or removing one that does not, is not an error: added and removed answer false.

curl -s $SUBSTRIO_URL/v1/_graph -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"labels":["follows","blocks"],"count":2}

Neighbors, degree and stats

curl -s "$SUBSTRIO_URL/v1/_graph/follows/neighbors/1" -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"label":"follows","node_id":1,"direction":"out","neighbors":[2,3],"count":2}

graph.neighbors (GET or POST /v1/_graph/{label}/neighbors/{id}) reads the out-neighbors of a node by default; POST with body {"dir": "in"} reads in-neighbors instead. graph.degree (GET /v1/_graph/{label}/degree/{id}) answers {"label", "node_id", "out_degree", "in_degree"}. graph.stats (GET /v1/_graph/{label}/stats) answers {"label", "edge_count"}. A node with no edges answers zero counts and an empty neighbor list; there is no separate not-found error for an unknown node or edge.

Analytics

graph.analytics (GET or POST /v1/_graph/{label}/analytics) runs one algorithm, named in body op, over a label. Every reply opens with {"op", "label"} plus the algorithm's own fields.

Pairwise similarity (take a, b): common_neighbors, jaccard, adamic_adar, preferential_attachment, overlap_coefficient, cosine_similarity, resource_allocation, exclusive_neighbors, neighbor_union.

curl -s -X POST "$SUBSTRIO_URL/v1/_graph/follows/analytics" -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' -d '{"op":"jaccard","a":1,"b":2}'
# {"op":"jaccard","label":"follows","a":1,"b":2,"dir":"out","score":0.4}

Whole-graph algorithms: pagerank, betweenness_centrality, closeness_centrality, hits, scc (strongly connected components), connected_components, louvain (community detection), triangle_count_global, global_clustering_coefficient, topological_sort, has_cycle, graph_summary, degree_histogram, degree_distribution.

Per-node and path algorithms (take node, or src/dst): degree_centrality, clustering_coefficient, k_hop_neighbors, two_hop_neighbors, shortest_path, shortest_path_length, all_shortest_paths, reachable, eccentricity.

dir ("out" or "in", default "out") applies to every directional algorithm. An unlisted op, or a request missing the fields that op needs, answers 400.

Mutation safety

Edge writes are not versioned and carry no idempotency key, but they are idempotent by nature: adding or removing the same edge twice has the same effect as once (added/removed answers false the second time).