如何在给定起始节点类型和允许的关系类型的情况下使用cypher OR TraversalDescription API获取所有连接的子图

时间:2017-07-26 19:24:28

标签: java neo4j cypher

我想获取图中所有连接的子图,它们由两个关系Rel1和Rel2连接。我有一个起始节点类型(不是确切的节点)。

目前我有以下基本查询,它给出了从n1到n2的所有路径,从2到10跳。

CYPHER 2.3 MATCH p = (n1:H)-[r:Rel1|Rel2*2..10]-(n2:H) WITH nodes(p) as result return result

但我需要连接这些路径的连接子图。任何建议或起点都会有所帮助。

我试过的其他事情是TraversalDescription java API进行深度优先搜索,但是它不采用起始节点类型而是采用特定的起始节点?

附上我的图表示例以及我对查询的期望。 enter image description here

2 个答案:

答案 0 :(得分:1)

[增订]

expanding subgraphs有几个APOC程序。

apoc.path.subgraphNodes似乎与您的用例最直接相关。有一些使用here的例子。

这是一个稍微简化的示例,它也使用apoc.periodic.commit(重复执行Cypher查询,直到它返回0或NULL)和apoc.coll.subtract(从一个集合中减去另一个集合)。在此示例中,创建Temp节点以保留临时数据,并在最后删除它。返回的result应该是对象的集合。每个对象都有一个subgraph_ids集合,其中包含属于同一子图的节点的本机ID。

MATCH (n:H)-[:Rel1|Rel2]-(:X)-[:Rel1|Rel2]-(:H)
WITH COLLECT(DISTINCT ID(n)) AS ids
CREATE (x:Temp {ids: ids, result: []})
WITH x
CALL apoc.periodic.commit(
  "MATCH (x:Temp) " +
  "CALL apoc.path.subgraphNodes(x.ids[0], {relationshipFilter:'Rel1|Rel2', labelFilter:'H|X', filterStartNode:false, limit:-1}) YIELD node " +
  "WITH x, COLLECT(ID(node)) AS subgraph_ids " +
  "SET x.ids = apoc.coll.subtract(x.ids, subgraph_ids) " +
  "SET x.result = x.result + {subgraph_ids: subgraph_ids} " +
  "RETURN SIZE(x.ids);"
  ,
  NULL) YIELD updates
WITH x, x.result AS result
DELETE x
RETURN result;

顶部的MATCH子句查找属于具有至少2个H和/或Rel1关系的子图的Rel2个节点。这些节点的本机ID用于初始化ids节点的Temp集合。

apoc.periodic.commit执行的Cypher代码将重复执行:

  • ids
  • 获取第一个ID
  • 获取子图中的节点(包含Rel|Rel2类型和X|H标签),其中包含具有该ID的节点
  • ids
  • 中减去子图节点的ID
  • 将包含子图节点ID集合的对象添加到result节点的Temp集合
  • 返回ids集合的当前大小(如果为0,则apoc.periodic.commit将完成执行。)

您可以修改此查询以返回实际节点,过滤具有特定标签的节点,等等。

答案 1 :(得分:0)

[增订]

一般情况下,我建议您考虑为Evaluator编写自定义TraversalDescription课程。在那里,您可以根据节点或关系类型轻松包含/排除/修剪等。将Evaluator视为一组规则,您的遍历将针对它找到的每个Path重复引用这些规则。这是一个基本的例子。

评估员:

public class MyEvaluator implements Evaluator {
    Label someLabel; 

    @Override
    public execute(Path path) {

        if (path.length() == 0) {
            return Evaluation.EXCLUDE_AND_CONTINUE;
        }

        if (path.lastRelationship().getEndNode().hasLabel(someLabel)) {
            return Evaluation.INCLUDE_AND_CONTINUE;
        }
        return Evaluation.EXCLUDE_AND_PRUNE;
    }
}

然后将其插入TraversalDescription:

public Stream<Path> myTraversal(Node startNode) {    
    GraphDatabaseService db;

    TraversalDescription td = db.getTraversalDescription().evaluator(new MyEvaluator()).depthFirst();

    Traverser tv = td.traverse(someStartNode);
    return tv.stream();
}

您是将它放在存储过程还是嵌入式实例中?