Overview
In the Relational Knowledge Graph System (RKGS) you typically work with data organized into a knowledge graph. Most graph algorithms, however, operate on unlabeled graphs. Rel’s Graph Library is designed to work with these unlabeled graphs. It provides constructors for creating graphs with the correct schema.
Graphs in Rel
Schema
A graph in Rel is a module containing the following relations:
node
is a set containing the nodes of the graph.edge
is a set of pairs of nodes.is_directed
distinguishes directed graphs from undirected graphs.
Only unweighted graphs are directly supported. See Weighted Nodes and Weighted Edges for details.
To create a graph, apply one of the graph constructor modules to a binary edge set:
// read query
// Define a binary edge set containing pairs of nodes.
def my_edges = {(1, 2); (1, 3); (2, 3)}
// Create a directed graph with nodes and edges from `my_edges`.
def my_graph = directed_graph[my_edges]
// Instantiate rel:graphlib on my_graph.
@inline
def my_graphlib = rel:graphlib[my_graph]
// Display the contents of `my_graph`.
def output = my_graph
Typically, data for the graph are stored in
base relations,
such as data imported from a CSV file.
The my_edges
, my_graph
, and my_graphlib
relations are persisted to a
model
so that they may be reused in other
queries.
See Create a Graph From a CSV File and Create a Graph From a Knowledge Graph for examples of creating graphs from external data.
Performance Tips
Although nodes may have any data type, many of the Graph Library’s relations perform better with integer nodes. To convert nodes to integers, you can install a module that transforms the edges and provides a mapping to get nodes back from their integer index:
// model
@inline
module transform[E]
// Map integers to nodes.
// The set of nodes is inferred from the edge set E as the
// union of all of the nodes in the first and second columns of E.
def int_to_node = enumerate[{first[E]; second[E]}]
// Reverse mapping to go from nodes to integers.
def node_to_int = transpose[int_to_node]
// The transformed edge set.
def edge = (node_to_int[u], node_to_int[v]) from u, v where E(u, v)
end
// Sample usage:
// Declare an edge set with mixed node types.
// Node "a" is a String, node 1.25 is a Float,
// and node 2023-05-12 is a Date literal.
def my_edge = {("a", 1.25); (1.25, 2023-05-12)}
// Transform the nodes and edges.
// Note that this is installed so that the mapping relations
// may be used in future queries to retrieve actual node values.
def transformed = transform[my_edge]
// Construct a directed graph from the transformed edge set.
def my_graph = directed_graph[transformed:edge]
The nodes of the graph are integers:
// read query
// Display the contents of my_graph.
def output = my_graph
To recover the original node from an integer,
partially apply
the int_to_node
relation to the node’s integer index:
// read query
// Display the original node corresponding to node 3.
def output = transformed:int_to_node[3]