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

时间:2018-05-22 10:14:40

标签: neo4j cypher query-performance property-graph

我使用的是Neo4j的Property Graph和Cypher。如标题中所述,我试图删除一些节点,这些节点可以从另一个节点到达而不通过其他节点,只有1个传入关系。以下是此案例:

Example graph

每个节点都有自己的标签(粗体,粗体字符)和名为nodeId的属性,这在节点中是唯一的。关系标签被省略,因为我们不能因为某些原因而依赖它。 nodeId属性已使用唯一约束进行索引。

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

  • 可以从A {nodeId: 1} 到达而无需传递另一个A标签节点
  • 只有1个传入关系

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

以下是我的Cypher代码:

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 个答案:

答案 0 :(得分:1)

由于您只关心是否有A路径,因此您应该使用shortestPath而不是(a)-[*]->(b)。这样,Cypher只需找到1个有效路径而不是所有可能的路径(这可以在更大的集合中保存)另外,您可以使用TAIL来切断列表中的第一项,以便您可以(Cypher可以)跳过那张支票。

根据您的Neo4j版本,使用MATCH <path> WHERE <stuff> WITH DISTINCT startnode ,endnode可能会更有效,因为后来的Cypher Planners可以使用WITH DISTINCT提示进行更快,更少详尽的路径匹配。在早期版本中,这将挂起Neo4j,您将需要使用APOC neo4j库。

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 Planners中表现更好。您可能需要将其更改为&#34; e的所有父母都包含在路径&#34;如果这是e可以有超过2个传入关系但仍需要删除的情况。

如果您的逻辑变得比那更复杂(删除哪些节点可以更改其他节点可以删除的内容

答案 1 :(得分:1)

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可以按方向过滤,但目前存在一个错误,它不允许我们只指定没有类型的关系方向。

更新

自2018年的APOC夏季版本(3.3.x线上的3.3.0.4和3.4.x线上的3.4.0.2)起,您现在可以在relationshipFilter中指定无类型,仅方向:{{1 }}