Graph Analytics#

The RelationalAI (RAI) Python API provides a Graph class for creating graphs from entities and relationships in a model. In this guide, you’ll learn how to create Graph objects and run graph algorithms.

Table of Contents#

Graphs#

Graphs are comprised of:

Before you can create a graph, you first need to define entities and relationships in the model.

In a sense, models are a kind of graph. Entities are like nodes, and relationships, such as properties, are like edges. What a graph represents, then, is a subset — sometimes called a projection — of the model’s entities and relationships that can be visualized and analyzed using graph algorithms.

Note that the graphs created with the Graph class are not labeled property graphs and do not retain the structure of the model. Graphs are homogenous, meaning they have only one type of node and one type of edge. They are primarily used for running graph algorithms on a subset of the model’s entities and relationships.

For the examples in this section, we’ll use the following model:

#import relationalai as rai

model = rai.Model("MyModel")
Person = model.Type("Person")
Product = model.Type("Product")

with model.rule():
    # Define some Product entities.
    flashlight = Product.add(description="Flashlight")
    batteries = Product.add(description="Batteries")
    toothpaste = Product.add(description="Toothpaste")

    # Define some Person entities.
    alice = Person.add(name="Alice")
    bob = Person.add(name="Bob")
    carol = Person.add(name="Carol")

    # Define a multi-valued friends property that connect Person entities.
    alice.friends.extend([bob, carol])
    bob.friends.add(alice)
    carol.friends.add(alice)

    # Define a multi-valued purchases property that connect Person and Product entities.
    alice.purchases.extend([flashlight, batteries])
    bob.purchases.add(batteries)

This model has three Product entities and three Person entities:

The friends and purchases properties are multi-valued and represent relationships between entities:

We’ll use this model to create two different graph objects, one for each relationship type.

Create a Directed Graph#

A directed graph is a graph where edges have a direction. That is, an edge from node A to node B is not the same as an edge from node B to node A.

Directed graphs model asymmetric relationships, such as the purchases relationship between Person and Product entities in the preceding model described above. The following snippet creates a directed graph from the model:

#from relationalai.std.graphs import Graph

# Create a graph object from the model.
purchases_graph = Graph(model)

# Add nodes to the graph.
purchases_graph.Node.extend(Person)
purchases_graph.Node.extend(Product)

# Add edges to the graph.
purchases_graph.Edge.extend(Person.purchases)

# Visualize the graph.
purchases_graph.visualize()

Let’s break down the code, step by step:

  1. First, you must import the Graph class from the relationalai.std.graphs module.

  2. Then, you instantiate a Graph object from the model. By default, the Graph constructor creates a directed graph. If you prefer to be explicit, you may set the undirected parameter to False:

    #purchases_graph = Graph(model, undirected=False)
    
  3. You add nodes to the graph using the purchase_graph.Node type. Here, .extend() is used to add all Person and all Product entities to the graph.

  4. You add edges to the graph using the purchase_graph.Edge class. Unlike Node, the Edge class is not a Type. However, it does have an .extend() method that you can use to add edges to the graph based on a property in the model.

  5. Finally, you can visualize the graph using the .visualize() method. In a Jupyter notebook, this method will render an interactive visualization of the graph below the cell. In non-interactive environments, the method will open a new browser tab with the visualization.

    IMPORTANT

    Graph visualizations are currently not supported in Snowflake notebooks.

    For this graph, the visualization looks like this:

    There are two isolated nodes in the graph. These are nodes that are not connected to any other nodes by edges. In this case, the isolated nodes represent the toothbrush, since no one has purchased it, and Carol, since she has not purchased any products.

    Because the graph is directed, the edges have arrows indicating the direction of the relationship. Note that the nodes are not labeled in the visualization. See the Graph Visualization guide for details on customizing the visualization.

Create an Undirected Graph#

An undirected graph is a graph where edges do not have a direction. An edge from node A to node B is the same as an edge from node B to node A.

Undirected graphs model symmetric relationships, such as the friends relationship between Person entities in the preceding model described above. The following snippet creates an undirected graph from the model:

#from relationalai.std.graphs import Graph

# Create a graph object from the model. Set the `undirected` parameter to `True`
# to create an undirected graph.
friends_graph = Graph(model, undirected=True)

# Add nodes to the graph.
friends_graph.Node.extend(Person)

# Add edges to the graph.
friends_graph.Edge.extend(Person.friends)

# Visualize the graph.
friends_graph.visualize()

The code is similar to the directed graph example, except that the undirected parameter is set to True when creating the Graph object.

Here’s the visualization of the undirected graph:

Edges in undirected graphs do not have arrows, indicating that the relationships are symmetric. See the Graph Visualization guide for details on customizing the visualization.

Limitations#

Nodes#

A graph’s node set is an instance of the Node class, which is a subclass of Type. To illustrate how to work with nodes, we’ll use the following model:

#import relationalai as rai

model = rai.Model("MyModel")
Person = model.Type("Person")
Product = model.Type("Product")

with model.rule():
    # Define some Product entities.
    flashlight = Product.add(description="Flashlight")
    batteries = Product.add(description="Batteries")
    toothpaste = Product.add(description="Toothpaste")

    # Define some Person entities.
    alice = Person.add(name="Alice")
    bob = Person.add(name="Bob")
    carol = Person.add(name="Carol")

    # Define a multi-valued purchases property that connect Person and Product entities.
    alice.purchases.extend([flashlight, batteries])
    bob.purchases.add(toothbrush)

Add Nodes to a Graph#

There are three ways to add nodes to a graph:

  1. Add all entities of a Type to the graph using the Node.extend() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add all Person entities as nodes in the graph.
    purchases_graph.Node.extend(Person)
    
    # Add all Product entities as nodes in the graph.
    purchases_graph.Node.extend(Product)
    
  2. Add specific entities to the graph using the Node.add() method inside of a model.rule() block:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add specific Person entities as nodes in the graph.
    with model.rule():
        purchases_graph.Node.add(Person(name="Alice"))
    
    # Add specific Product entities as nodes in the graph.
    with model.rule():
        purchases_graph.Node.add(Product(description="Flashlight"))
        purchases_graph.Node.add(Product(description="Batteries"))
    
  3. Automatically add nodes when edges are added to the graph:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add all Person entities as nodes in the graph.
    purchases_graph.Node.extend(Person)
    
    # Add edges to the graph from the Person.purchases property. Products that
    # people have purchased are automatically added to the graph as nodes.
    purchases_graph.Edge.extend(Person.purchases)
    

    In the example above, each Person entity is added to the graph. Then edges are created from the Person.purchases property. This automatically adds the flashlight and batteries products to the graph’s node set. The toothbrush product is not added to the node set because it is not connected to any Person entities by the purchases property.

Remove Nodes from a Graph#

There is no way to directly remove nodes from a graph. You declare graphs and their nodes in your Python code. A graph is not materialized until it is queried or visualized.

To remove nodes from a graph, you must redeclare the graph without the nodes you want to remove. You could do this by either:

  1. Editing the code that adds nodes to the graph to exclude the nodes you want to remove.

  2. Creating a new graph object and add only the nodes you want to keep:

    ## Create a copy of the purchases_graph without the node for Alice.
    purchases_graph_without_alice = Graph(model)
    
    with model.rule():
       # Get all Person entities that are nodes in the purchases_graph.
       person = Person(purchases_graph.Node)
       # Exclude Alice.
       person.name != "Alice"
       # Add all remaining Person entities as nodes in the new graph.
       purchases_graph_without_alice.Node.add(person)
    
    with model.rule():
       # Get all edges in the purchases_graph.
       edge = purchases_graph.Edge()
       # Exclude edges that connect to Alice.
       alice = Person(name="Alice")
       edge.from_ != alice
       edge.to != alice
       # Add all remaining edges to the new graph.
       purchases_graph_without_alice.Edge.add(from_=edge.from_, to=edge.to)
    

Set Properties on Nodes#

Nodes support both single-valued and multi-valued properties. There are four ways to set properties on nodes:

  1. Pass single-valued properties to keyword arguments of the Node.extend() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add all Person entities as nodes in the graph. Set the label property of
    # each node to the Person's name.
    purchases_graph.Node.extend(Person, label=Person.name)
    
  2. Pass single-valued properties to keyword arguments of the Node.add() method inside of a model.rule() block:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add specific Person entities as nodes in the graph. Set the label property
    # of each node to the Person's name.
    with model.rule():
        alice = Person(name="Alice")
        purchases_graph.Node.add(alice, label=alice.name)
    
  3. Set single-valued properties on node instances using the .set() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Set the label property of each node to the Person's name.
    with model.rule():
        person = Person()
        node = purchases_graph.Node.add(person)
        node.set(label=person.name)
    
  4. Set multi-valued properties on nodes:

    # from relationalai.std.graphs import Graph
    
     # Create a graph object from the model.
     purchases_graph = Graph(model)
    
     # Add edges to the graph from the Person.purchases property.
     purchases_graph.Edge.extend(Person.purchases)
    
     # Set a neighbors property of each node.
     with model.rule():
         node = purchases_graph.Node()
         neighbor = purchases_graph.Edge(from_=node).to
         node.neighbors.add(neighbor)
    

Query Properties of Nodes#

Properties set on nodes can be queried by getting an Instance of a graph’s Node type and selecting the properties you want:

#from relationalai.std.graphs import Graph

purchases_graph = Graph(model)
purchases_graph.Node.extend(Person, label=Person.name)
purchases_graph.Edge.extend(Person.purchases)

with model.query() as select:
   # Get an instance of the graph.Node() type.
   node = purchases_graph.Node()
   # Select the label property of each node.
   response = select(node.label)

# Display the results.
print(response.results)
#    label
# 0  Alice
# 1    Bob
# 2  Carol

Nodes cannot directly access properties of the entities they represent. For instance, although each node in the graph is a Person entity, you cannot access the Person entity’s name property directly from the node:

#with model.query() as select:
    node = purchases_graph.Node()
    # The following raises an UninitializedProperty warning.
    response = select(node.name)

# --- Uninitialized property -----------------------------------------------------

# The property graph224_name has never been set or added to and so will always
# cause the rule or query to fail.

#   1 |  with model.query() as select:
#   2 |      node = purchases_graph.Node()
#   3 |      response = select(node.name)

# --------------------------------------------------------------------------------

To access the name property, you may either:

  1. Set the name property on the node when you add it to the graph:

    #purchases_graph.Node.extend(Person, name=Person.name)
    
    # Now the following query works:
    with model.query() as select:
       node = purchases_graph.Node()
       # The following raises an UninitializedProperty warning.
       response = select(node.name)
    
    print(response.results)
    #     name
    # 0  Alice
    # 1    Bob
    # 2  Carol
    

    See Set Properties on Nodes for details.

  2. Get an Instance of the Person type, filter it for people who are nodes in the graph, and select the name property:

    #with model.query() as select:
        # Get people who are also nodes in the graph.
        person = Person(purchases_graph.Node)
        # Select the name property of each person.
        response = select(person.name)
    
    print(response.results)
    #     name
    # 0  Alice
    # 1    Bob
    # 2  Carol
    

    This approach is more flexible than setting properties on nodes because it allows you to access any property of the Person entity, not just those set on the node.

    Note that person = Person(purchase_graph.Node) is equivalent to:

    #person = Person()
    purchase_graph.Node(person)
    

    See Filtering Objects by Type for more information.

Edges#

A graph’s edge set is an instance of the Edge class. Edge is analogous to a Type in that it represents a set of things – namely the edges of the graph. However, Edge is not a subclass of Type because edges are not entities in the model.

Instances of edges are represented by the EdgeInstance class, which is analogous to an Instance of a Type. EdgeInstance objects have two special properties named from_ and to that represent the nodes at either end of the edge.

To illustrate how to work with edges, we’ll use the following model:

#import relationalai as rai

model = rai.Model("MyModel")
Person = model.Type("Person")
Product = model.Type("Product")

with model.rule():
    # Define some Product entities.
    flashlight = Product.add(description="Flashlight")
    batteries = Product.add(description="Batteries")
    toothpaste = Product.add(description="Toothpaste")

    # Define some Person entities.
    alice = Person.add(name="Alice")
    bob = Person.add(name="Bob")
    carol = Person.add(name="Carol")

    # Define a multi-valued friends property that connect Person entities.
    alice.friends.extend([bob, carol])
    bob.friends.add(alice)
    carol.friends.add(alice)

    # Define a multi-valued purchases property that connect Person and Product entities.
    alice.purchases.extend([flashlight, batteries])
    bob.purchases.add(toothbrush)

Add Edges to a Graph#

There are two ways to add edges to a graph:

  1. Add all edges defined by a property to the graph using the Edge.extend() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add edges to the graph from the Person.purchases property. Note that entities
    # that are connected by the purchases property are automatically added to the
    # nodes of the graph.
    purchases_graph.Edge.extend(Person.purchases)
    
  2. Add specific edges to the graph using the Edge.add() method inside of a model.rule() block:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add specific edges to the graph. Connect Alice to the Flashlight and Batteries
    # products. Note that Alice, Flashlight, and Batteries are automatically added to
    # the graph's node set.
    with model.rule():
        alice = Person(name="Alice")
        purchases_graph.Edge.add(from_=alice, to=Product(description="Flashlight"))
        purchases_graph.Edge.add(from_=alice, to=Product(description="Batteries"))
    

    This method allows you to add edges that are not defined by a property in the model. For example, you could add edges from an entity that connects to multiple other entities, such as a Purchase entity that connects a Person entity to a Product entity:

    ## Define a Purchase type.
    Purchase = model.Type("Purchase")
    
    # Add some Purchase entities to the model.
    with model.rule():
       Purchase.add(by=Person(name="Alice"), product=Product(description="Flashlight"), quantity=1)
       Purchase.add(by=Person(name="Bob"), product=Product(description="Batteries"), quantity=2)
    
    # Add edges to the graph from the Purchase entities.
    with model.rule():
       purchase = Purchase()
       purchases_graph.Edge.add(from=purchase.by, to=purchase.product)
    

    Note that calling .add() multiple times with the same from_ and to arguments does not create multiple edges between the same pair of nodes, since multigraphs are not supported. Only one edge is created between the nodes and no error is raised.

Remove Edges from a Graph#

There is no way to directly remove edges from a graph. You declare graphs and their edges in your Python code. A graph is not materialized until it is queried or visualized.

To remove edges from a graph, you must redeclare the graph without the edges you want to remove. You could do this by either:

  1. Editing the code that adds edges to the graph to exclude the edges you want to remove.

  2. Creating a new graph object and add only the edges you want to keep:

    ## Create a copy of the purchases_graph without the edges involving Batteries.
    purchases_graph_without_edges = Graph(model)
    
    # Add all of the nodes from the purchases_graph to the new graph.
    purchases_graph_without_edges.Node.extend(purchases_graph.Node)
    
    with model.rule():
       # Get all edges in the purchases_graph.
       edge = purchases_graph.Edge()
       # Exclude edges that connect to Flashlight.
       batteries = Product(description="Flashlight")
       edge.from_ != batteries
       edge.to != batteries
       # Add all remaining edges to the new graph.
       purchases_graph_without_edges.Edge.add(from_=edge.from_, to=edge.to)
    

Set Properties on Edges#

Edges support only single-valued properties. There are three ways to set properties on edges:

  1. Pass properties to keyword arguments of the Edge.extend() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add edges to the graph from the Person.purchases property. Set the label
    # property of each edge to the string "purchased."
    purchases_graph.Edge.extend(Person.purchases, label="purchased")
    
  2. Pass properties to keyword arguments of the Edge.add() method inside of a model.rule() block:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add specific edges to the graph. Connect Alice to Flashlight and set the
    # label to the string "purchased."
    with model.rule():
        alice = Person(name="Alice")
        purchases_graph.Edge.add(from_=alice, to=Product(description="Flashlight"), label="purchased")
    

    Avoid calling .add() multiple times with the same from_ and to arguments. Although it is possible to do so without error, the behavior is undefined:

    #with model.rule():
        alice = Person(name="Alice")
        flashlight = Product(description="flashlight")
        purchases_graph.Edge.add(from_=alice, to=flashlight, label="purchased")
        # The following does not create a new edge between Alice and the flashlight,
        # and the label property of the existing edge is not guaranteed to be updated.
        purchases_graph.Edge.add(from_=alice, to=flashlight, label="bought")
    

    Since multigraphs are not supported, only one edge is created between the nodes. Moreover, the property’s value is indeterminate. Edge properties, like label, behave like single-valued properties of other entities in the model. Two values have been declared, but only one will be used and there’s no guarantee it will always be the first or the last value.

  3. Set properties on edge instances using the EdgeInstance.set() method:

    #from relationalai.std.graphs import Graph
    
    # Create a graph object from the model.
    purchases_graph = Graph(model)
    
    # Add edges from the Person.purchases property to the graph.
    purchases_graph.Edge.extend(Person.purchases)
    
    # Set the label property of each edge to the string "purchased."
    with model.rule():
        edge = purchases_graph.Edge()
        edge.set(label="purchased")
    

Query Properties of Edges#

Properties set on edges can be queried by getting an EdgeInstance from a graph’s Edge set and selecting the properties you want:

#from relationalai.std.graphs import Graph

purchases_graph = Graph(model)
purchases_graph.Edge.extend(Person.purchases)

# Get the entities at either end of the edge.
with model.query() as select:
    edge = purchases_graph.Edge()
    response = select(edge.from_.name, edge.to.name)

print(response.results)
#     name       name2
# 0  Alice  Flashlight
# 1  Alice   Batteries
# 2    Bob   Batteries

Every edge instance has from_ and to properties that return Instance objects representing the nodes at either end of the edge. Properties of the nodes can be accessed directly from the Instance objects. In a directed graph, like the purchase_graph in the preceding example, from_ is the source node and to is the target node.

In an undirected graph, from_ and to are not interchangeable. The direction of the edge is determined by the order in which the nodes are added to the edge:

#friends_graph = Graph(model, undirected=True)
friends_graph.Edge.extend(Person.friends)

with model.query() as select:
   edge = friends_graph.Edge()
   edge.from_ == Person(name="Alice")
   response = select(edge.from_.name, edge.to.name)

print(response.results)
#     name  name2
# 0  Alice    Bob
# 1  Alice  Carol

with model.query() as select:
   edge = friends_graph.Edge()
   edge.to == Person(name="Alice")
   response = select(edge.from_.name, edge.to.name)

print(response.results)
# Empty DataFrame
# Columns: []
# Index: []

The Person.friends property connects Alice to Bob and Carol. Even though the graph is undirected, Alice is considered the source node and Bob and Carol are considered target nodes.

You can ensure that from_ and to are interchangeable by adding a rule that makes the Person.friends relationship symmetric:

#with model.rule():
    # Make the Person.friends relationship symmetric.
    person = Person()
    friend = person.friends
    friend.friends.add(person)

with model.query() as select:
    edge = friends_graph.Edge()
    response = select(edge.from_.name, edge.to.name)

print(response.results)
#     name  name2
# 0  Alice    Bob
# 1  Alice  Carol
# 2    Bob  Alice
# 3  Carol  Alice

Weighted Graphs#

Edges in a graph may be weighted, meaning they have a numerical value associated with them. To create a weighted graph, you must set the weighted parameter to True when creating the Graph object and set the weight property on the edges:

#import relationalai as rai
from relationalai.std.graphs import Graph

model = rai.Model("MyModel")
Person = model.Type("Person")
Friendship = model.Type("Friendship")

# Add some Person entities and Friendship relationships to the model.
with model.rule():
   alice = Person.add(name="Alice")
   bob = Person.add(name="Bob")
   carol = Person.add(name="Carol")
   Friendship.add(person1=alice, person2=bob, years_known=2)
   Friendship.add(person1=alice, person2=carol, years_known=5)

# Create a weighted graph object from the model.
friends_graph = Graph(model, undirected=True, weighted=True)

# Add edges to the graph from the Friendship type. The weight of each edge is
# set to the years_known property of the Friendship relationship.
with model.rule():
    friendship = Friendship()
    friends_graph.Edge.add(
        from_=friendship.person1,
        to=friendship.person2,
        weight=friendship.years_known
    )

# Show the edges and their weights.
with model.query() as select:
    edge = friends_graph.Edge()
    response = select(edge.from_.name, edge.to.name, edge.weight)

print(response.results)
#     name  name2  v
# 0  Alice    Bob  2
# 1  Alice  Carol  5
IMPORTANT

Edge weights should be non-negative numerical values such as integers, floats, or decimals. Floating-point infinity and NaN values are not supported. Edges with non-numeric edge weights are ignored by graph algorithms and may result in unexpected results.

Both directed and undirected graphs may be weighted. Any edges that are not explicitly given a weight are assigned a default weight of 1.0.

Just like other single-valued properties, you should avoid setting an edges’ weight property multiple times. For instance, the following is invalid:

#with model.rule():
    friendship = Friendship()
    edge = friends_graph.Edge.add(
        from_=friendship.person1,
        to=friendship.person2,
        weight=friendship.years_known
    )
    # The following does not update the weight of the edge. It creates an edge with
    # an indeterminate weight value.
    edge.set(weight=friendship.years_known + 1)

# Querying the model will result in an error:
with model.query():
    edge = friends_graph.Edge()
    response = select(edge.from_.name, edge.to.name, edge.weight)

# --- Integrity constraint violation ---------------------------------------------
#
# The provided weight relation must not contain multiple-weight edges.
#
#   17 |  friends_graph = Graph(model, undirected=True, weighted=True)
#
# --------------------------------------------------------------------------------

In some cases, however, you may want to update the edge weights in a graph. To do so, you must create a new graph with the same nodes and edges but with different weights:

## Create a new graph.
new_graph = Graph(model)

# Add nodes from friends_graph to the new graph.
new_graph.Node.extend(friends_graph.Node)

# Add edges from friends_graph to the new graph with updated weights.
with model.rule():
    edge = friends_graph.Edge()
    new_graph.Edge.add(
        from_=edge.from_,
        to=edge.to,
        weight=edge.weight + 1
    )

Graph Algorithms#

Instances of the Graph class have a .compute namespace that provides access to several graph algorithms.

For example, consider the following graph of Person and Product entities:

#import relationalai as rai
from relationalai.std.graphs import Graph

model = rai.Model("MyModel")
Person = model.Type("Person")
Product = model.Type("Product")

# Define some Person and Product entities.
with model.rule():
    flashlight = Product.add(description="Flashlight")
    batteries = Product.add(description="Batteries")
    toothpaste = Product.add(description="Toothpaste")

    alice = Person.add(name="Alice")
    bob = Person.add(name="Bob")
    carol = Person.add(name="Carol")

    alice.purchases.extend([flashlight, batteries])
    bob.purchases.add(batteries)

# Create a graph object from the model.
purchases_graph = Graph(model)

# Add edges to the graph using the Person.purchases property.
purchases_graph.Edge.extend(Person.purchases)

For example, you can calculate the number of nodes and edges in the graph using the .compute.num_nodes() and .compute.num_edges() methods:

#from relationalai.std import alias

with model.query() as select:
   num_nodes = purchases_graph.compute.num_nodes()
   num_edges = purchases_graph.compute.num_edges()
   response = select(
      alias(num_nodes, "num_nodes"),
      alias(num_edges, "num_edges")
   )

print(response.results)
#    num_nodes  num_edges
# 0          4          3

Not all graph algorithms are available for all types of graphs. For instance, the Louvain community detection algorithm is only available for undirected graphs and will raise an error if called from a directed graph:

#with model.query() as select:
    node = purchases_graph.Node()
    # The following raises a DirectedGraphNotSupported error.
    community_id = purchases_graph.compute.louvain(node)
    response = select(node, community_id)

Some algorithms, such as PageRank, may be fine-tuned using additional parameters to control the algorithm’s behavior:

#with model.query() as select:
    node = purchases_graph.Node()
    # Calculate the PageRank of each node in the graph with a damping factor of 0.8.
    pagerank = purchases_graph.compute.page_rank(node, damping_factor=0.8)
    response = select(node, pagerank)

Refer to the reference docs for each algorithm, provided below, for details on the parameters they accept and the graph types they support.

Basic Statistics#

NameDescriptionReturns
.num_edges()Get the number of edges in the graph.Expression
.num_nodes()Get the number of nodes in the graph.Expression

Degree#

NameDescriptionReturns
.degree(node)Compute the degree of a node.Expression
.indegree(node)Compute the indegree of a node.Expression
.outdegree(node)Compute the outdegree of a node.Expression

Centrality Measures#

NameDescriptionReturns
.betweenness_centrality(node)Compute the betweenness centrality of a node.Expression
.degree_centrality(node)Compute the degree centrality of a node.Expression
.eigenvector_centrality(node)Compute the eigenvector centrality of the graph.Expression
.pagerank(node)Compute the PageRank of a node.Expression

Similarity Measures#

NameDescriptionReturns
.cosine_similarity(node1, node2)Compute the cosine similarity between two nodes.Expression
.jaccard_similarity(node1, node2)Compute the Jaccard similarity between two nodes.Expression
NameDescriptionReturns
.adamic_adar(node1, node2)Compute the Adamic-Adar index between two nodes.Expression
.common_neighbor(node1, node2)Find the common neighbors between two nodes.Expression
.preferential_attachment(node1, node2)Compute the preferential attachment score between two nodes.Expression

Community Detection#

NameDescriptionReturns
.infomap()Assign a community label to each node using the Infomap algorithm.Expression
.is_triangle(node1, node2, node3)Check if three nodes form a triangle.Expression
.label_propagation(node)Assign a community label to node using the label propagation algorithm.Expression
.louvain(node)Assign a community label to node using the Louvain algorithm.Expression
.num_triangles()Compute the number of triangles in the graph.Expression
.triangles()Find all unique triangles in the graph.tuple of three Expression objects.
.triangle_community(node)Assign a community label to node using the percolation method.Expression

Clustering#

NameDescriptionReturns
.avg_clustering_coefficient()Compute the average clustering coefficient of the graph.Expression
.local_clustering_coefficient(node)Compute the local clustering coefficient of a node.Expression

Connectivity#

NameDescriptionReturns
.is_connected()Check if the graph is connected.Expression
.is_reachable(node1, node2)Check if node2 is reachable from node1.Expression
.reachable_from(node)Find all nodes reachable from node.Expression
.weakly_connected_component(node)Find the weakly connected component containing node.Expression

Distance#

NameDescriptionReturns
.diameter_range()Compute lower and upper bounds for the diameter of a graph.tuple of two Expression objects.
.distance(node1, node2)Compute the shortest path length between two nodes. Ignores weights in weighted graphs.Expression