使用Cypher获取指定结构的树

2022-09-02 10:28:35 浏览数 (1)

@TOC[1] Here's the table of contents:

•一、来自社区的问题链接•二、编写查询实现数据封装 •2.1 创建样例数据 •2.2 Cypher实现

使用Cypher获取指定结构的树

一、来自社区的问题链接

Neo4j 图数据库中文社区:如何获取指定结构的树?[2]

但是相同层级的node我希望去除重复项后作为一个数组,比如下图:

但是简单的这样处理后会丢失父节点以及关系,我希望每个节点转换为一个map对象,这个对象包含了原本的节点,以及父节点的id,关系的名称方便在客户端直接序列化 可是我试了好多办法,只能对单列这样处理,多列就变成笛卡尔积了!

二、编写查询实现数据封装

2.1 创建样例数据

2.2 Cypher实现

分层封装数据获取指定结构的树,返回结果中每一层每个节点包含该节点关联的关系ID、节点ID;如果需要在返回结果中包含节点、关系属性和类型信息,可以在对应Cypher查询位置处进行封装一并返回。

代码语言:javascript复制
// 匹配需要处理的路径
MATCH p=(c:Class {name:'电影'})-[r1:实例]->(m:Movie)<-[r2:ACTED_IN]-(:Person) 
    // 收集两层关系
    WITH COLLECT(DISTINCT r1) AS hc_r1,COLLECT(DISTINCT r2) AS hc_r2
    // 解析第一层NODE,第二层NODE,第三层NODE
    // NODE对象结构:node-当前层节点,f_node表示父级节点,rel表示当前节点的关系
    WITH REDUCE(l=[],r IN hc_r1 | l apoc.map.setPairs({},[["node",ID(STARTNODE(r))],["rel",ID(r)]])) AS hc_n1,
        REDUCE(l=[],r IN hc_r1 | l apoc.map.setPairs({},[["f_node",ID(STARTNODE(r))],["node",ID(ENDNODE(r))],["rel",ID(r)]])) AS hc_n2,
        REDUCE(l=[],r IN hc_r2 | l apoc.map.setPairs({},[["f_node",ID(ENDNODE(r))],["node",ID(STARTNODE(r))],["rel",ID(r)]])) AS hc_n3
    // 通过上一次处理后,每一层节点、关联关系以及父级节点都准备好了,下一步需要将`node`排重,然后将`f_node`和`rel`收集在一个数组
    // 当前节点的父级节点和关联关系可能有多个,所以排重后需要增加两个map字段`f_nodes`和`rels`
    WITH hc_n1,hc_n2,hc_n3
    WITH apoc.map.groupByMulti(hc_n1,'node') AS hc_n1_gp,EXTRACT(map IN hc_n1 | map.node) AS hc_n_l1, 
        apoc.map.groupByMulti(hc_n2,'node') AS hc_n2_gp,EXTRACT(map IN hc_n2 | map.node) AS hc_n_l2, 
        apoc.map.groupByMulti(hc_n3,'node') AS hc_n3_gp,EXTRACT(map IN hc_n3 | map.node) AS hc_n_l3
    // 封装最终返回的每一层数据格式[{cur_node:node,f_nodes:[2,123],rels:[213,23]}]
    WITH REDUCE(l=[],nd IN hc_n_l1 | l apoc.map.setPairs({},[["cur_node",nd],["f_nodes",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n1_gp,TOSTRING(nd),NULL,FALSE) | mp.f_node) WHERE e IS NOT NULL))],["rels",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n1_gp,TOSTRING(nd),NULL,FALSE) | mp.rel) WHERE e IS NOT NULL))]])) AS hc1,
        REDUCE(l=[],nd IN hc_n_l2 | l apoc.map.setPairs({},[["cur_node",nd],["f_nodes",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n2_gp,TOSTRING(nd),NULL,FALSE) | mp.f_node) WHERE e IS NOT NULL))],["rels",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n2_gp,TOSTRING(nd),NULL,FALSE) | mp.rel) WHERE e IS NOT NULL))]])) AS hc2,
        REDUCE(l=[],nd IN hc_n_l3 | l apoc.map.setPairs({},[["cur_node",nd],["f_nodes",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n3_gp,TOSTRING(nd),NULL,FALSE) | mp.f_node) WHERE e IS NOT NULL))],["rels",apoc.coll.toSet(FILTER(e IN EXTRACT(mp IN apoc.map.get(hc_n3_gp,TOSTRING(nd),NULL,FALSE) | mp.rel) WHERE e IS NOT NULL))]])) AS hc3
// 使用apoc.coll.toSet排重列表
RETURN apoc.coll.toSet(hc1) AS hc1,
        apoc.coll.toSet(hc2) AS hc2,
        apoc.coll.toSet(hc3) AS hc3

References

[1] TOC: 使用Cypher获取指定结构的树 [2] Neo4j 图数据库中文社区:如何获取指定结构的树?: http://neo4j.com.cn/topic/619ab67c03dea95514def1b1

0 人点赞