代码之家  ›  专栏  ›  技术社区  ›  Triet Doan

如何有效地删除从另一个节点可以到达而不经过其他节点且只有一个传入关系的节点?

  •  2
  • Triet Doan  · 技术社区  · 6 年前

    删除可以从另一个节点访问但不传递其他节点且只有一个传入关系的节点数

    Example graph

    每个节点都有其标签(大的粗体字符)和一个名为 nodeId 节点ID 属性已使用唯一约束索引。

    现在,从节点开始 A {nodeId: 1} ,我要删除它和所有其他节点:

    • 可从 一个{nodeId:1} .

    因此,将删除的节点有: 一个{nodeId:1} , B {nodeId: 3} , C {nodeId: 4} ,和 C {nodeId: 8} .

    MATCH p = (s:A {nodeId: 1 }) -[*1..10]-> (e)
    WHERE NONE (x in NODES(p) WHERE x:A AND NOT x.nodeId = 1)
    WITH s, e
    MATCH (e) <-[r]- ()
    WITH count(r) AS num_r, s, e
    WHERE num_r < 2
    DETACH DELETE e
    DETACH DELETE s
    

    代码运行得很好,但是随着我的图表的增长,它变得越来越慢。一开始,它只需要不到10毫秒,但现在,当我有大约100万个节点和200万个关系时,它需要超过1秒。

    我应该做些什么来提高代码的性能?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Tezra    6 年前

    既然你只在乎有没有一条路,你应该用 shortestPath 而不是仅仅 (a)-[*]->(b) TAIL 删除列表中的第一项,以便(Cypher可以)跳过该检查。

    根据您的Neo4j版本,使用 MATCH <path> WHERE <stuff> WITH DISTINCT startnode ,endnode

    MATCH (s:A {nodeId: 1 })
    WITH s MATCH p=shortestPath((s)-[*1..10]->(e))
    WHERE NONE (x in TAIL(NODES(p)) WHERE x:A) AND NOT ()-->(e)<--()
    WITH DISTINCT s, e
    DETACH DELETE e
    DETACH DELETE s
    

    你也可以改变 NOT ()-->(e)<--() SIZE(()-->(e)) < 2 如果你需要更改那个号码。不过,前者在一些Cypher计划者身上可能表现得更好。您可能需要将其更改为“路径中包含e的所有父级”,如果这种情况下e可以有两个以上的传入关系,但仍需要删除。

        2
  •  1
  •   InverseFalcon    6 年前

    Tezra对这个查询的Cypher版本有正确的想法(但是没有使用shortestPath())。

    APOC Procedures ,它具有路径扩展过程,可以很好地为您的用例工作,只查找到每个不同节点的单个路径,并在标签上有效地过滤。

    下面是您可能使用的方法,使用 apoc.path.subgraphNodes()

    MATCH (s:A {nodeId: 1 })
    CALL apoc.path.subgraphNodes(s, {maxLevel:10, labelFilter:'-A'}) YIELD node as e
    WITH s, e 
    WHERE size((e)<--()) = 1
    DETACH DELETE e
    WITH distinct s
    DETACH DELETE s
    

    过程调用中的labelFilter确保扩展中没有节点具有 :A

    编辑

    虽然relationshipFilter可以按方向进行筛选,但目前有一个bug不允许我们只指定没有类型的关系方向。

    更新

    自2018年APOC夏季发行版(3.3.0.4沿3.3.x线,3.4.0.2沿3.4.x线)起,您现在只能在relationshipFilter中指定无类型、方向: relationshipFilter:'>'