Traversal Framework examples

The following are some examples of how you can use the Traversal Framework. The source code for the examples can be found in TraversalExample.java.

traversal framework example

This graph illustrates a small group of friends with the definition of RelationshipType:

private enum Rels implements RelationshipType
{
    LIKES, KNOWS
}

Traversing a graph examples

The graph can be traversed with, for example, the following traverser starting at the node with the name = 'Joe':

for ( Path position : db.traversalDescription()
        .depthFirst()
        .relationships( Rels.KNOWS )
        .relationships( Rels.LIKES, Direction.INCOMING )
        .evaluator( Evaluators.toDepth( 5 ) )
        .traverse( node ) )
{
    output += position + "\n";
}

The traversal will thus output:

(0)
(0)<-[LIKES,1]-(5)
(0)<-[LIKES,1]-(5)-[KNOWS,6]->(1)
(0)<-[LIKES,1]-(5)-[KNOWS,6]->(1)<-[KNOWS,5]-(6)
(0)<-[LIKES,1]-(5)-[KNOWS,6]->(1)-[KNOWS,4]->(4)
(0)<-[LIKES,1]-(5)-[KNOWS,6]->(1)-[KNOWS,4]->(4)-[KNOWS,3]->(3)
(0)<-[LIKES,1]-(5)-[KNOWS,6]->(1)-[KNOWS,4]->(4)-[KNOWS,3]->(3)-[KNOWS,2]->(2)

Since TraversalDescription is immutable, it is useful to create template descriptions that include common settings shared by different traversals. For example, start with this traverser:

friendsTraversal = db.traversalDescription()
        .depthFirst()
        .relationships( Rels.KNOWS )
        .uniqueness( Uniqueness.RELATIONSHIP_GLOBAL );

It yields the following output (starting from the node with the name = 'Joe'):

(0)
(0)-[KNOWS,0]->(2)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)<-[KNOWS,4]-(1)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)<-[KNOWS,4]-(1)<-[KNOWS,6]-(5)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)<-[KNOWS,4]-(1)<-[KNOWS,5]-(6)

Then, create a new traverser from it, restricting depth to three:

for ( Path path : friendsTraversal
        .evaluator( Evaluators.toDepth( 3 ) )
        .traverse( node ) )
{
    output += path + "\n";
}

This should be the output:

(0)
(0)-[KNOWS,0]->(2)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)

In case you want to traverse from depth 2 to 4:

for ( Path path : friendsTraversal
        .evaluator( Evaluators.fromDepth( 2 ) )
        .evaluator( Evaluators.toDepth( 4 ) )
        .traverse( node ) )
{
    output += path + "\n";
}

This gives the following output:

(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)
(0)-[KNOWS,0]->(2)<-[KNOWS,2]-(3)<-[KNOWS,3]-(4)<-[KNOWS,4]-(1)

For other useful evaluators, see Using Evaluators.

The Traverser also has a nodes() method, which returns an Iterable of all the nodes in the paths:

for ( Node currentNode : friendsTraversal
        .traverse( node )
        .nodes() )
{
    output += currentNode.getProperty( "name" ) + "\n";
}

This gives the following output:

Joe
Sara
Peter
Dirk
Lars
Lisa
Ed

You can do this with relationships as well. Here is an example:

for ( Relationship relationship : friendsTraversal
        .traverse( node )
        .relationships() )
{
    output += relationship.getType().name() + "\n";
}
KNOWS
KNOWS
KNOWS
KNOWS
KNOWS
KNOWS

Implementing a user-defined procedure

This example shows how to implement a user-defined procedure using the Traversal Framework. The transaction and logger are made available through the Procedure Framework:

@Context
public Transaction tx;

@Context
public Log log;

@Procedure(value = "traverse.findPeople")
@Description("Finds all the known people to the given Person")
public Stream<PathResult> findFriends(@Name("person") Node person) {

    final Traverser traverse = tx.traversalDescription()
            .breadthFirst()
            .relationships(RelationshipType.withName("KNOWS"), Direction.OUTGOING)
            .evaluator(Evaluators.toDepth(5))
            .evaluator(new PathLogger())
            .traverse(person);

    return stream(traverse.iterator()).map(PathResult::new);
}

private final class PathLogger implements Evaluator {

    @Override
    public Evaluation evaluate(Path path) {
        log.info(path.toString());
        return Evaluation.INCLUDE_AND_CONTINUE;
    }
}

This allows the Traversal Framework to be used side by side with Cypher:

MATCH (p:Person { name: 'Joe' })
CALL traverse.findPeople(p) YIELD path RETURN [friend IN nodes(path) | friend.name] AS friends