ExOKF.Graph.Backend behaviour (ex_okf v0.1.0)

Copy Markdown View Source

Behaviour for OKF graph backends.

Backends turn a loaded ExOKF.Bundle into a traversable directed graph whose nodes are concept ids and whose edges come from internal markdown links.

The native adjacency backend ships in v0.1. The GraphBLAS backend is an ExOKF extension (not part of the OKF standard); full sparse acceleration lands in v0.2.

Types

  • graph/0 — opaque backend-specific graph structure
  • concept_id/0 — OKF concept id (String.t()), e.g. "tables/orders"

Example implementation

A minimal adjacency-style backend:

defmodule MyApp.TinyGraph do
  @behaviour ExOKF.Graph.Backend

  @impl true
  def build(%ExOKF.Bundle{} = bundle) do
    # Build your representation from bundle.concepts and their links
    ExOKF.Graph.Adjacency.build(bundle)
  end

  @impl true
  def neighbors(graph, id), do: ExOKF.Graph.Adjacency.neighbors(graph, id)

  @impl true
  def reverse_neighbors(graph, id), do: ExOKF.Graph.Adjacency.reverse_neighbors(graph, id)

  @impl true
  def reachable(graph, id, opts \\ []), do: ExOKF.Graph.Adjacency.reachable(graph, id, opts)

  @impl true
  def has_edge?(graph, from, to), do: ExOKF.Graph.Adjacency.has_edge?(graph, from, to)

  @impl true
  def edges(graph), do: ExOKF.Graph.Adjacency.edges(graph)

  @impl true
  def node_count(graph), do: ExOKF.Graph.Adjacency.node_count(graph)

  @impl true
  def edge_count(graph), do: ExOKF.Graph.Adjacency.edge_count(graph)
end

Then select it when indexing:

bundle = ExOKF.Graph.index(bundle, MyApp.TinyGraph)
ExOKF.Graph.neighbors(bundle, "tables/orders")

Summary

Types

OKF concept identifier — the file path within the bundle with .md removed.

Opaque graph structure owned by a backend.

Callbacks

Builds a graph from the bundle's concepts and internal links.

Returns the number of directed edges in the graph.

Returns all directed edges as {from, to} tuples, sorted.

Returns true when a directed edge from → to exists.

Returns sorted outbound neighbor concept ids of id.

Returns the number of concept nodes in the graph.

Returns concept ids reachable from id.

Returns sorted inbound neighbor concept ids (backlinks) of id.

Types

concept_id()

@type concept_id() :: String.t()

OKF concept identifier — the file path within the bundle with .md removed.

Examples

"tables/orders"
"datasets/sales"
"playbooks/incident-response"

graph()

@type graph() :: term()

Opaque graph structure owned by a backend.

Concrete shapes include ExOKF.Graph.Adjacency.t() and ExOKF.Graph.GraphBLAS.t(). Callers should treat this as an opaque term().

Callbacks

build(t)

@callback build(ExOKF.Bundle.t()) :: graph()

Builds a graph from the bundle's concepts and internal links.

Parameters

  • bundle (ExOKF.Bundle.t()) — loaded OKF bundle

Returns

A backend-specific graph/0 value later passed to the other callbacks.

Example

@impl true
def build(%ExOKF.Bundle{} = bundle) do
  ExOKF.Graph.Adjacency.build(bundle)
end

edge_count(graph)

@callback edge_count(graph()) :: non_neg_integer()

Returns the number of directed edges in the graph.

Parameters

Example

@impl true
def edge_count(graph), do: ExOKF.Graph.Adjacency.edge_count(graph)

edges(graph)

@callback edges(graph()) :: [{concept_id(), concept_id()}]

Returns all directed edges as {from, to} tuples, sorted.

Parameters

Returns

Example: [{"tables/orders", "tables/customers"}, {"tables/orders", "datasets/sales"}].

Example

@impl true
def edges(graph), do: ExOKF.Graph.Adjacency.edges(graph)

has_edge?(graph, concept_id, concept_id)

@callback has_edge?(graph(), concept_id(), concept_id()) :: boolean()

Returns true when a directed edge from → to exists.

Parameters

Example

@impl true
def has_edge?(graph, from, to) do
  ExOKF.Graph.Adjacency.has_edge?(graph, from, to)
end

neighbors(graph, concept_id)

@callback neighbors(graph(), concept_id()) :: [concept_id()]

Returns sorted outbound neighbor concept ids of id.

Parameters

Returns

A list of concept ids, e.g. ["datasets/sales", "tables/customers"].

Example

@impl true
def neighbors(graph, id), do: ExOKF.Graph.Adjacency.neighbors(graph, id)

node_count(graph)

@callback node_count(graph()) :: non_neg_integer()

Returns the number of concept nodes in the graph.

Parameters

Example

@impl true
def node_count(graph), do: ExOKF.Graph.Adjacency.node_count(graph)

reachable(graph, concept_id, keyword)

@callback reachable(graph(), concept_id(), keyword()) :: [concept_id()]

Returns concept ids reachable from id.

Parameters

  • graph (graph/0) — graph from build/1
  • id (concept_id/0) — start concept id
  • opts (keyword()) — supported options:
    • :max_depth (pos_integer() \| :infinity) — hop limit (default :infinity)
    • :include_self (boolean()) — include id in the result (default false)

Returns

A sorted list of reachable concept ids.

Example

@impl true
def reachable(graph, id, opts \\ []) do
  ExOKF.Graph.Adjacency.reachable(graph, id, opts)
end

reverse_neighbors(graph, concept_id)

@callback reverse_neighbors(graph(), concept_id()) :: [concept_id()]

Returns sorted inbound neighbor concept ids (backlinks) of id.

Parameters

Returns

A list of concept ids that link to id.

Example

@impl true
def reverse_neighbors(graph, id) do
  ExOKF.Graph.Adjacency.reverse_neighbors(graph, id)
end