Skip to content

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.

Rel Graph Schema

A graph in Rel is a module containing some or all of the following relations:

  1. node is a set containing the nodes of the graph. Every graph has a node relation.
  2. edge is a set of pairs of nodes. Every graph has an edge relation.
  3. weight is a set of triples that map edges to numeric weights. Only weighted graphs have a weight relation.
  4. is_directed distinguishes directed graphs from undirected graphs.
  5. is_weighted distinguished weighted graph from unweighted graphs.

For example, the following module represents a weighted, directed graph with two nodes and one edge with a weight of 1.0:

module my_graph
    def edge = {(1, 2)}
    def node = {1; 2}
    def weight = {(1, 2, 1.0)}
    def :is_directed = true
    def :is_weighted = true
end

You may easily create modules with valid graph schemas using the create_graph, undirected_graph, and directed_graph constructors described in Creating Graphs. 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

For the best performance, use integer node IDs. To convert non-integer nodes to integers, install the following module, which transforms an edge relation to pairs of integers and provides a mapping to get the original nodes back from their integer ID:

// 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]
 
    // Define 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]
Was this doc helpful?