遍历框架示例

以下是一些关于如何使用遍历框架的示例。这些示例的源代码可以在 TraversalExample.java 中找到。

traversal framework example

此图说明了一小组朋友以及 RelationshipType 的定义

private enum Rels implements RelationshipType
{
    LIKES, KNOWS
}

遍历图示例

例如,可以使用以下遍历器从名称为 'Joe' 的节点开始遍历此图

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

因此,遍历将输出以下内容

(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)

由于 TraversalDescription 是不可变的,因此创建包含不同遍历共享的常用设置的模板描述非常有用。例如,从以下遍历器开始

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

它会产生以下输出(从名称为 '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)

然后,从中创建一个新的遍历器,将深度限制为三

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

输出应如下所示

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

如果您想从深度 2 遍历到深度 4

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

这将给出以下输出

(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)

有关其他有用的评估器,请参见 使用评估器

Traverser 还有一个 nodes() 方法,它返回路径中所有节点的 Iterable

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

这将给出以下输出

Joe
Sara
Peter
Dirk
Lars
Lisa
Ed

您也可以对关系执行此操作。以下是一个示例

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

实现用户定义的过程

此示例演示了如何使用遍历框架实现 用户定义的过程。事务和日志记录器通过过程框架提供

@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;
    }
}

这允许遍历框架与 Cypher 并排使用

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