Traversal框架 neo4j
2016-02-16 17:10
232 查看
2.5.2. Traversal框架(Java版本)
发表于2012 年 7 月 27 日 由
neo4j
2.5.2.1. TraversalDescription
2.5.2.2. Evaluator
2.5.2.3. Traverser
2.5.2.4. Uniqueness
2.5.2.5. Order
2.5.2.6. BranchSelector
2.5.2.7. Path
2.5.2.8. PathExpander/RelationshipExpander
2.5.2.9. Expander
2.5.2.10. 如何使用Traversal框架
traversal框架由除了
Node和
Relationship以外的一系列主要接口组合而成:
TraversalDescription,
Evaluator,
Traverser和
Uniqueness是最主要的.
Path在遍历中也有一定的用途, 因为在评价一个位置他用来表示一个位置。此外,
PathExpander(或者
RelationshipExpander) 和
Expander接口也属于traversals,但用户使用他们时需要自己实现。这里有大量的接口的高级用法,当在遍历时要求明确控制顺序时:
BranchSelector,
BranchOrderingPolicy和
TraversalBranch。
2.5.2.1. TraversalDescription
TraversalDescription是用于定义和初始化traversals的最主要接口。并不意味着要由用户实现,而是由traversal框架作为一个描述traversals的方法提供。
TraversalDescription的实例是不可改变的,他的方法返回一个新的
TraversalDescription,相对对象来说,这个方法可以通过带参数修改调用。
关系
增加一个关系类型到traverse的关系列表中。默认情况下,列表是空的,意味着将遍历所有关系,不管什么类型。如果一个或者更多的关系被加入到列表中,那么就只会遍历增加的类型。这里有两个方法,一个是包括方向,另外一个是排除方向,都被包括在双向中。2.5.2.2. Evaluator
Evaluator用在决定,在每一个位置(用
Path表示):是应该继续遍历,是/否在结果中包含节点。给一个
路径,要求指定四个分支中的一个:
Evaluation.INCLUDE_AND_CONTINUE: 在结果中包括这个节点并继续遍历
Evaluation.INCLUDE_AND_PRUNE: 在结果中包括这个节点并不再遍历
Evaluation.EXCLUDE_AND_CONTINUE: 在结果中不包括这个节点并继续遍历
Evaluation.EXCLUDE_AND_PRUNE: 在结果中不包括这个节点并不再遍历
可以配置不只一个evaluator。注意evaluator会被遍历中遇到的每一个位置所调用,包括起点。
2.5.2.3. Traverser
Traverser对象是调用
traverse()的结果。他表明了遍历在图中的位置,以及返回结果格式的规范。实际的遍历都是赖允许的,只有当调用迭代器中的
next()方法才会真正调用
Traverser。
2.5.2.4. Uniqueness
当一个遍历启动后,在Uniqueness中设置那些位置可以被重新访问。默认情况下,设置成:
NODE_GLOBAL。
一个由TraversalDescription提供的Uniqueness可以表明可以被重新访问的相同位置的情况。不同的uniqueness等级如下:
NONE- 在图中任何位置都可以被多次访问。
NODE_GLOBALuniqueness – 在整个图中,没有节点可以被访问超过一次。这会消耗大量内存,因为他要求保存所有访问过的节点到内存中。
RELATIONSHIP_GLOBALuniqueness – 在整个图中,没有关系可以被访问超过一次。这会消耗大量内存,因为他要求保存所有访问过的关系到内存中。
NODE_PATHuniqueness – 节点不会出现在之前路径出现过的地方。
RELATIONSHIP_PATHuniqueness – 关系不会出现在之前路径出现过的地方。
NODE_RECENTuniqueness – 是相对于NODE_GLOBAL的简化,表明有一个曾经访问过的节点的全局集合。然而这个等级设置有一个内存消耗的上限,他的集合只包括最近访问过的节点。这个集合的大小可以通过方法TraversalDescription.uniqueness()的第二个参数来指定。
RELATIONSHIP_RECENTuniqueness – 跟NODE_RECENT工作原理类似,只是用关系代替了节点。
宽度优先 / 深度优先
有一些方法专门用于设置BranchSelector|ordering的宽度优先/深度优先策略。调用
Traversal factory里面的
order方法可以达到同样的效果,或者开发你自己的
BranchSelector/BranchOrderingPolicy。
2.5.2.5. Order
深度优先/宽度优先方法的一般版本允许通过一个随意的BranchOrderingPolicy被注入description到中。
2.5.2.6. BranchSelector
一个BranchSelector是用来设置traversal下一步将遍历哪一个分支。这个一般用来实现遍历顺序。traversal框架提供了一个基本的顺序实现:Traversal.preorderDepthFirst()- 遍历深度优先, 在访问他的子节点之前访问其他每一个节点。
Traversal.postorderDepthFirst()- 遍历深度优先, 在访问他的子节点之后访问其他每一个节点。
Traversal.preorderBreadthFirst()- 遍历宽度优先, 在访问他的子节点之前访问其他每一个节点。
Traversal.postorderBreadthFirst()- 遍历宽度优先, 在访问他的子节点之后访问其他每一个节点。
Note | |
---|---|
请注意宽度优先比深度优先消耗更多的内存。 |
Traversal框架的一个用户很少需要自己实现BranchSelector或者BranchOrderingPolicy,图算法已经提供了。Neo4j图算法包包含了一些范例,说明BranchSelector/BranchOrderingPolicy中用的一些算法,比如A* 和 Dijkstra。
BranchOrderingPolicy
创建BranchSelectors的工厂决定了返回的分支方向(分支的位置用Path表示)。一般的策略是
宽度优先和
深度优先。举个例子,调用
TraversalDescription#depthFirst():
description.order( Traversal.preorderDepthFirst() ); |
TraversalBranch
被BranchSelector使用的一个对象从某一个分支获取更多的分支。本质上,有一个由一个路径和一个RelationshipExpander(用来从当前分支中获取更多新的TraversalBranch)复合组成。
2.5.2.7. Path
一个路径也是Neo4j API接口的一部分。在traversal API中,路径的用法是双重的。Traversers可以返回他们自己的结果,这些结果由在图中被访问过的并且标记成需要被返回的路径组成。路径对象在图中也被用于路径的评估,用于判断traversal在某个点是否继续或者某个点是否应该包括在结果中。2.5.2.8. PathExpander/RelationshipExpander
traversal使用PathExpanders (取代 RelationshipExpander) 发现关系,通过这些关系,可以从一个指定的路径遍历更多的分支出来。2.5.2.9. Expander
注入RelationshipExpander到关系中的一般情况是定义遍历的所有关系。默认情况下,一个默认的expander会被使用,任何其他关系的顺序都无法保证。为了保证在关系类型的顺序中的关系被遍历,还有另外一种实现方式,在其中关系的类型是被新增的。
Expander接口继承了
RelationshipExpander,确保他能自定义
Expander。
TraversalDescription的实现使用这个提供定义关系类型的方法,
在
TraversalDescription内部构建一个
RelationshipExpander,是用户使用API的一种常用方法。
被Neo4j框架提供的所有RelationshipExpanders也实现了Expander接口。对于traversal API的一个用户来说,实现PathExpander/RelationshipExpander接口变得更加容易,因为他之需要包括一个方法,这个方法用于从路径/节点中获取关系,Expander接口增加的方法之用于构建新的Expanders。
2.5.2.10. 如何使用Traversal框架
图2.5.2.10.1. Traversal 范例图定义
RelationshipTypes:
private enum Rels implements RelationshipType { LIKES, KNOWS } |
for ( Path position : Traversal.description() .depthFirst() .relationships( Rels.KNOWS ) .relationships( Rels.LIKES, Direction.INCOMING ) .evaluator( Evaluators.toDepth( 5 ) ) .traverse( node ) ) { output += position + "\n" ; } |
(7) (7)<--[LIKES,1]--(4) (7)<--[LIKES,1]--(4)--[KNOWS,6]-->(1) (7)<--[LIKES,1]--(4)--[KNOWS,6]-->(1)--[KNOWS,4]-->(6) (7)<--[LIKES,1]--(4)--[KNOWS,6]-->(1)--[KNOWS,4]-->(6)--[KNOWS,3]-->(5) (7)<--[LIKES,1]--(4)--[KNOWS,6]-->(1)--[KNOWS,4]-->(6)--[KNOWS,3]-->(5)--[KNOWS,2]-->(2) (7)<--[LIKES,1]--(4)--[KNOWS,6]-->(1)<--[KNOWS,5]--(3) |
TraversalDescription是不可改变的,所以创建descriptions模版来在不同的遍历中共享使用是个不错的方法。举个例子,让我们开始遍历:
final TraversalDescription FRIENDS_TRAVERSAL = Traversal.description() .depthFirst() .relationships( Rels.KNOWS ) .uniqueness( Uniqueness.RELATIONSHIP_GLOBAL ); |
(7) (7)--[KNOWS,0]-->(2) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6)<--[KNOWS,4]--(1) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6)<--[KNOWS,4]--(1)<--[KNOWS,5]--(3) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6)<--[KNOWS,4]--(1)<--[KNOWS,6]--(4) |
for ( Path path : FRIENDS_TRAVERSAL .evaluator( Evaluators.toDepth( 3 ) ) .traverse( node ) ) { output += path + "\n" ; } |
(7) (7)--[KNOWS,0]-->(2) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6) |
for ( Path path : FRIENDS_TRAVERSAL .evaluator( Evaluators.fromDepth( 2 ) ) .evaluator( Evaluators.toDepth( 4 ) ) .traverse( node ) ) { output += path + "\n" ; } |
(7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6) (7)--[KNOWS,0]-->(2)<--[KNOWS,2]--(5)<--[KNOWS,3]--(6)<--[KNOWS,4]--(1) |
如果你对路径没有兴趣,你可以像下面这样将遍历后的节点转换成节点迭代器:
for ( Node currentNode : FRIENDS_TRAVERSAL .traverse( node ) .nodes() ) { output += currentNode.getProperty( "name" ) + "\n" ; } |
Joe Sara Peter Dirk Lars Ed Lisa |
for ( Relationship relationship : FRIENDS_TRAVERSAL .traverse( node ) .relationships() ) { output += relationship.getType() + "\n" ; } |
KNOWS KNOWS KNOWS KNOWS KNOWS KNOWS |
相关文章推荐
- iOS中关于证书签发者无效的问题
- shell脚本expect命令send特殊字符
- python 转换 Javascript %u 字符串为 python unicode
- linux系统的安装
- linux 查看系统信息
- getDimension方法的一些坑
- Android EventBus开源项目
- 纵表和横表的概念及其相互转换
- InnovEDA PowerPCB/BGA Suite 4.0.1 + InnovEDA Visual HDL V6.7.8 for Verlog
- 怎样让pl sql developer 界面视图复位
- debian服务器上不了网,缺少默认网关
- Overview of Flashback Technology
- linux下 SCP 、ssh、ssh-copy-id采用非默认端口传输
- vim ctags omnicppcomplete 无法自动提示成员变量,总是提示“找不到模式”的解决方法
- php将一个数值切成N份
- RHCE 学习笔记(23) - 磁盘格式化和分区
- UIView常用的一些方法小记之setNeedsDisplay和setNeedsLayout
- 钣金CAD/CAM系统 Cnckad v10.066 全能破解版 1CD
- 转载 loadrunner的一些问题解决
- 下载、运行docker