Java如何去解析Neo4j返回的Record
前言
Neo4j是一个可以构建节点关系的非关系型的图数据库,通过使用Neo4j存储数据,我们可以很好地实现一些节点关系数据,比如物流中的运输路线等。
对于第一次使用Neo4j的朋友来说,解析查询记录是很痛苦的,本文记录了几种常用的处理查询结果的方法,以便不时之需。
操作
如果查询返回的是m,r,n
正如下述Neo4j查询语句,返回的记录是两个节点的信息及其关系:
1 | MATCH (n) -[r]- (m) RETURN n,r,m |
我们可以这样去解析:
1 | // 获取节点n的数据 |
注意:上述的r,n,m要与cypher语句中的对应
如果返回的是一条路径 path = (xxx)
在我们物流的路线规划业务中,往往会有最短距离路线和最低成本路线的选取,而这是返回的路线数据是比较复杂的,正如下面 cypher
查询:
1 | MATCH path = shortestPath((n:n_Label) -[*..{}]- (m:m_Label)) |
此时我们获取到的 record
是 节点n
到 节点m
的整条路径的值,包括一个开始节点(n)、结束节点(m)。
以及从开始节点到结束节点之间经过的每两个节点间的片段segements:
segments:[{startNode, relationship, endNode},{xxx},{xxx}]
此时,如果我们想要获取record中的某一条线路的值,我们可以通过 record.get(x)
来获取(注意:x为第x条线路,因为我们这里的最短线路只有一条线路,所以 record.get(0)
即可以获取到),这里获取到的就是我们的path值,是Value接口类型的。
record.get(0)
的结果:
Value接口类型是一个类似于Map的接口,这里我们不好处理,所以我们要将其转换为PathValue(PathValue是Value类型的一个实现类可以获取到Path,Path类型处理结果方便)。
1 | // 将第一条记录格式化成path-> path |
转换成path之后,我们可以看到path里面的值
在这里,我们可以查看一下path源码,看一下nodes、relationships、segments
的值分别是什么
通过上述代码以及注释我们可以发现:
nodes是Path类帮我们实现的一个迭代器,里面包含了整条路径涉及到的所有的node
relationships同上,里面封装的是整条路线涉及到的节点之间的关系
segment是一个接口,segment其实就是我们某段关系的记录,包括开始节点、关系、接收节点,也就是对应的
n-r-m
。注意:segment是某一段关系,而一个节点到另外一个节点的中间,可能会有多段关系
上述cypher语句的查询路径如下图所示
注意:因为
shortestPath()
是有方向性的,所以这里只能查询到从a到b的结点如果要查询a到e之间的所有路线,我们把shortestPath去掉即可,但是一定要加排序并加limit加以限制,不然会造成OOM。
好的,言归正传,如果我们需要获取record中的node进行数据处理,只需要调用 path.nodes()
遍历即可
1 | // 这里我用的是Stream来处理数据 |
上面代码的执行流程:
将
nodes
转换为Stream流,用于遍历处理node因为node是一个接口并且其结构与Map类似,也是K-V键值对,所以我们在这里可以直接调用它的
asMap
方法将其转成map集合,用于后续数据处理Node接口的类图:
我们可以查看MapAcessor接口,看里面的方法
将Node转成Map之后,我们就可以用工具类对我们需要的实体类进行封装。
同理,relationship
的获取也是差不多。
1 | // 这里获取到的是一个迭代器,我们可以直接使用Stream遍历 |
上面获取cost的代码,执行流程是这样的
通过
StreamUtil.of(path.relationships())
将relationships转换为流。使用
mapToDouble
对Stream流做一个映射,映射的结果返回为double类型然后再映射过程中,将
relationship
转换成map,因为relationship是一个k-v键值对。relationship.asMap();
将relationship转为map然后获取
cost
属性,并且进行一个求和处理
如果返回的是一个统计结果
当然,如果我们对结果进行统计,这时想要获取record中的统计结果的话,我们直接获取即可。
1 | // 统计从n到m有多少条线路 |
比如上述cypher查询中,我们要获取c的值,直接get即可。
1 | Long result = Convert.toLong(record.get(0)) |