Neo4j:入门基础(八)之Traversal API
前言
Neo4j数据库的高性能查询表现就是根据图数据库结构的自然伸展特性,使用免索引邻近查询算法,即图的遍历来实现的。图的遍历是图数据结构所具有的独特算法。
根据遍历时查找数据的路径不同,遍历算法可以分为广度优先遍历(从起始节点访问更远的节点之前走得尽可能广)和深度优先遍历(以最快的速度达到图形的最深处)。
二叉树的深度优先遍历算法分为:先序遍历、中序遍历和后序遍历;
二叉树的广度优先遍历又称层次遍历;
官方文档:The traversal framework
了解深度优先遍历和广度优先遍历(可参阅《Neo4j in action》第八章):
图的深度优先遍历(DFS)和广度优先遍历(BFS)算法分析
Neo4j_事务&深度遍历
关系的起始与终止节点依赖于关系的方向,路径的起始与终止节点依赖于遍历顺序。
接口
①遍历描述接口(TraversalDescription):用于定义和初始化遍历的主接口。这并不是说要用户去实现遍历查询框架,而是相对于有框架提供的实现来说,这提供了一个用户自定义查询条件的方法。
②路径拓展接口(PathExpander):定义将要对图数据库中的什么进行遍历,一般是指 针对关系的指向和关系的类型进行遍历。
③评估器接口(Evaluator):用于在每个位置确定如果遍历继续,当前节点是否应包含在结果中。
- Evaluation.INCLUDE_AND_CONTINUE : 在结果中包括这个节点并继续遍历查询。
- Evaluation.INCLUDE_AND_PRUNE : 在结果中包括这个节点并不继续遍历查询。
- Evaluation.EXCLUDE_AND_CONTINUE : 从结果中排除这个节点且继续遍历查询。
- Evaluation.EXCLUDE_AND_PRUNE : 从结果中排除这个节点且不继续遍历查询。
④遍历器接口(Traverser):调用一个 TraversalDescription 的 traverse() 方法返回的结果。
⑤唯一性接口(Uniqueness):设定一个规则决定在遍历期间如何访问已经访问过的位置。默认规则是 NODE_GLOBAL 。
- NONE :在图数据库中任何节点都可以被重访。
- NODE_GLOBAL uniqueness :在图数据库中每个节点只能被访问一次。这会潜在的消耗大量的内存因为图要求保持一个内存中的数据结构用来保存所有被访问过的节点。
- RELATIONSHIP_GLOBAL uniqueness :在图数据库中每个关系只能被访问一次。这会潜在的消耗大量的内存因为图中一般关系的数量远远大于节点的数量。这种级别的内存开销会比NODE_GLOBAL uniqueness大。
- NODE_PATH uniqueness :一个节点不能在之前的遍历路径中出现过。
- RELATIONSHIP_PATH uniqueness :一个关系不能在之前的遍历路径中出现过。
- NODE_RECENT uniqueness :这是 NODE_GLOBAL uniqueness 的简化版,有一个全局访问过的节点集合在每个位置进行核对。这种级别不会消耗大量的内存因为这个集合只会包含最近访问过的节点。这个集合的尺寸可以通过方法 TraversalDescription.uniqueness() 的第二个参数来指定。
- RELATIONSHIP_RECENT uniqueness :跟NODE_RECENT uniqueness类似,只是换成关系而已。
⑥顺序接口(Order):例如深度优先或广度优先,深度优先是Neo4j默认的分支顺序策略。
案例
⭐完整代码请参照 链接
public enum RelTypes implements RelationshipType{HOME_NODE,KNOWS,CO_WORKER}public void createNodespace(){try ( Transaction tx = graphDb.beginTx() ){Node home = graphDb.createNode();homeNodeId = home.getId();Node user = graphDb.createNode();user.setProperty( "name", "User" );home.createRelationshipTo( user, RelTypes.HOME_NODE ); // 创建HOME和User关系Node one = graphDb.createNode();one.setProperty( "name", "One" );user.createRelationshipTo( one, RelTypes.KNOWS ); // 创建User和One关系Node first = graphDb.createNode();first.setProperty( "name", "First" );user.createRelationshipTo( first, RelTypes.KNOWS );// 创建User和First关系first.createRelationshipTo( one, RelTypes.KNOWS );// 创建First和One关系Node two = graphDb.createNode();two.setProperty( "name", "Two" );first.createRelationshipTo( two, RelTypes.KNOWS );// 创建First和Two关系Node three = graphDb.createNode();three.setProperty( "name", "Three" );two.createRelationshipTo( three, RelTypes.KNOWS );// 创建Two和Three关系Node four = graphDb.createNode();four.setProperty( "name", "Four" );three.createRelationshipTo( four, RelTypes.CO_WORKER );// 创建Three和Four关系tx.success();}}private Node getEndNode(Long id) //根据某节点ID获取其某关系下单向的目标节点{return graphDb.getNodeById(id).getSingleRelationship( RelTypes.HOME_NODE, Direction.OUTGOING ).getEndNode();}
广度优先遍历
查找朋友:代码中使用breadthFirst()设定了使用广度优先遍历算法,关系函数relationships()设定了关系的类型为KNOWS,同时设定查找的方向为单向,通过Evaluators.excludeStartPosition()设定了评估函数evaluator从开始节点进行查找。执行程序后,将从查找节点开始,找出由KNOWS关系连接的所有节点。
//广度优先private Traverser getFriends( final Node person ){TraversalDescription td = graphDb.traversalDescription().breadthFirst().relationships( RelTypes.KNOWS, Direction.OUTGOING ).evaluator( Evaluators.excludeStartPosition() );return td.traverse( person );}
public String printFriends(){try ( Transaction tx = graphDb.beginTx() ){Node neoNode = getEndNode(homeNodeId);int numberOfFriends = 0;String output = neoNode.getProperty( "name" ) + "'s friends:\n";Traverser friendsTraverser = getFriends( neoNode );for ( Path friendPath : friendsTraverser ){output += "At depth " + friendPath.length() + " => "+ friendPath.endNode().getProperty( "name" ) + "\n";numberOfFriends++;}output += "Number of friends found: " + numberOfFriends + "\n";return output;}}
运行结果:
深度优先遍历
查找朋友:代码中使用depthFirst()设定了使用深度优先遍历算法
//深度优先private Traverser getFriendsDepth( final Node person ){TraversalDescription td = graphDb.traversalDescription().depthFirst().relationships( RelTypes.KNOWS, Direction.OUTGOING ).evaluator( Evaluators.excludeStartPosition() );return td.traverse( person );}
运行结果:
小结
使用深度优先算法的结果和使用广度优先算法的结果不同。广度优先算法首先从User→One这条路径进行遍历,然后再查找第二条路径User→First→Two→Three;深度优先算法先从User→First→Two→Three这条路径进行遍历,再从First→One这条路径进行遍历
具体在应用中应该使用哪种算法,可根据实际情况来决定。例如:如果要查找One,可以使用广度优先遍历;如果要查找Three,则使用深度优先遍历会快一点;如果要查找First,则使用任何一种遍历算法的结果都是一样的。
其他:广度优先遍历比深度优先遍历需要更高的内存开销。
查找同事:如果从User节点开始,要查找出由同事关系CO_WORKER所连接的节点,则将没有直接的路径,它必须经过KNOWS关系才能找到,并且这个同事在最右边的最后一个节点之中。
代码通过depthFirst()设定了使用深度优先遍历算法,使用了两个关系函数relationships()来设计查找的路径,并在评估函数evaluator()中设定查找最终节点的CO_WORKER关系,所以使用这个查找算法可以查找出朋友中最后节点的同事。
private Traverser findWorker( final Node startNode ){TraversalDescription td = graphDb.traversalDescription().depthFirst().relationships( RelTypes.CO_WORKER, Direction.OUTGOING ).relationships( RelTypes.KNOWS, Direction.OUTGOING ).evaluator(Evaluators.includeWhereLastRelationshipTypeIs( RelTypes.CO_WORKER ) );return td.traverse( startNode );}
对于该测试数据,要查找同事,不管是使用广度优先遍历还是深度优先遍历,其查找结果没有什么不同,但查找的方法还是有所不同。广度优先算法首先从User→One这条路径进行遍历,然后再查找第二条路径User→First→Two→Three→Four;深度优先算法则只要查找第二条路径就可以了。
系列
Neo4j:入门基础(一)之安装与使用
Neo4j:入门基础(二)之导入CSV文件
Neo4j:入门基础(三)之APOC插件
Neo4j:入门基础(四)之Java API
Neo4j:入门基础(五)之SDN
Neo4j:入门基础(六)之从MySQL导入数据
Neo4j:入门基础(七)之Algo插件
Neo4j:入门基础(八)之Traversal API
来源
《Neo4j 全栈开发》陈韶健[著] 电子工业出版社 版次:2017年6月第1版
《Neo4j in Action(Neo4j 实战)》(英)阿列克萨·武科蒂奇 机械工业出版社 版次:2016年4月第1版
Neo4j:入门基础(八)之Traversal API相关推荐
- JavaScript 入门基础 (八)
目录 1.JavaScript概述 2.HTML世界 3.JavaScript基本语法 4.JavaScript语句 5.JavaScript内置对象 6.Document对象 7.window和fr ...
- Neo4j:入门基础(一)之安装与使用
# 图数据库 链接:什么是原生(Native)图数据库 一般认为具有"无索引邻接"特性的图数据库才称为原生图数据库 链接:常用的图数据库 图存储可以分为属性图.三元组存储和混合系统 ...
- GEE_API Docs_Tutorials_1.编程基础和Earth Engine API入门
API Docs_Tutorials_1.编程基础和Earth Engine API入门 一.Introduction to JavaScript for Earth Engine(JavaScrip ...
- 【AI白身境】搞计算机视觉必备的OpenCV入门基础
文章首发于微信公众号<有三AI> [AI白身境]搞计算机视觉必备的OpenCV入门基础 今天是新专栏<AI白身境>的第五篇. 曾经看过一个视频,树莓派自平衡机器人自动追着小球跑 ...
- Java入门基础及面试100题--初入门
Java入门基础及面试100题 注:适合应届毕业生或java初入门者 1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程, ...
- java入门基础教程(纯干货知识点+视频资源)
本套Java视频教程是黑马程序员冯老师精心录制的Java基础班视频,该视频专门针对零基础的学员录制,授课讲究通俗易懂.干货.通过该套Java视频教程的学习,相信你能够轻轻松松地入门java语言. 完整 ...
- Unity3D入门(八):物理组件之刚体与碰撞体
Unity3D入门(八):物理组件之刚体与碰撞体 准备工作 物理组件之刚体 刚体组件简介 使用刚体移动物体 遇到的问题 物理组件之碰撞体 碰撞体简介 碰撞体种类 Box Collider Sphere ...
- opencv入门基础(c++)【二】
opencv入门基础(c++) 七.绘制形状与文字 7.1使用cv::Point与cv::Scalar 7.2绘制线.矩形.园.椭圆等基本几何形状 绘制线 绘制矩形 绘制椭圆 绘制圆 绘制填充图形 7 ...
- **JAVA入门基础2**(系列更新)———JAVA 基础变量
**JAVA入门基础2**(系列更新)---JAVA 基础变量 Java基础 1.注释 2.标识符和关键字 2.1 标识符 2.2 关键字(keyword) 3.数据类型 3.1 基本数据类型 3.2 ...
最新文章
- Java 代码完成删除文件、文件夹操作
- ListView 与 RecyclerView的创建与使用的异同
- Android开发群
- WGCNA | weighted correlation network analysis
- qt利用QSplitter任意拆分窗口
- pythongui做计算器_python GUI之简易计算器
- 阿里布局物联网!开源操作系统 AliOS Things 喜提 1 亿芯片出货量
- 开源分布式数据库 TiKV 入选 CNCF 云原生项目!
- IOS 10 微信 ajax readystate=0 status=0 解决方法
- [PWA] Check Online Status by using the NavigatorOnLine API
- 数据结构之排序算法Java实现(8)—— 线性排序之计数排序算法
- win2012故障转移mysql集群_Windows下SQLSERVER故障转移集群案例
- 视频图像标准:D1/D2/D3/D4/D5
- Tess4j的使用(识别中文)
- iOS-QQ自动聊天机器人
- 中信证券显示连接服务器,我的中信证券的交易软件真不好用
- [宝塔]配置ssl证书,提示错误:证书错误,请粘贴正确的PEM格式证书
- 特征工程7种常用方法
- 计算机科学个人陈述中文,计算机专业个人陈述二十(计算机科学)
- 预测大盘最准确的指标_一辈子死记一个指标,完全弄透彻,即可预测一个月的股市升跌!...
热门文章
- uniapp实现app的强制更新
- ubuntu 16.04 + GTX1050安装nvidia驱动
- Mybatis官方网站
- BZOJ1050 [HAOI2006]旅行comf(Kruskal算法)
- rhel centos 源_Rhel centos 7的fips脚本
- 质量回顾分析系统软件(QRS)
- Android Studio怎么把查看代码的左箭头、右箭头图标加到右边的快捷工具栏
- java 计算器 junit测试_Java Junit测试
- [DAX] FORMAT函数
- dax和m的区别_DAX:一文透彻理解DAX本质