2

我正在使用来自 Neo4j 的 Property Graph 和 Cypher。如标题中所述,我正在尝试删除许多节点,这些节点可以从另一个节点到达而不通过其他节点,并且只有 1 个传入关系。下面是这个案例的例子:

示例图

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

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

  • A {nodeId: 1} 无需通过另一个 A-label 节点即可到达。
  • 只有 1 个传入关系

因此,将删除的节点是:A {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 秒。

我应该怎么做才能提高该代码的性能?

谢谢您的帮助。

4

2 回答 2

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 Summer 版本开始(沿 3.3.x 行的 3.3.0.4 和沿 3.4.x 行的 3.4.0.2),您现在可以在 relationshipFilter 中指定无类型、仅方向:relationshipFilter:'>'

于 2018-05-22T22:23:43.803 回答
1

由于您只关心是否存在 A 路径,因此您应该使用shortestPath而不是(a)-[*]->(b). 这样,Cypher 只需要找到 1 条有效路径而不是所有可能的路径(这可以成为较大集合中的救生员)此外,您可以使用TAIL切断列表中的第一项,以便您可以(Cypher 可以)跳过该检查。

根据您的 Neo4j 版本,UsingMATCH <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 Planner 中表现更好。如果在这种情况下 e 可以有超过 2 个传入关系但仍需要删除,则您可能需要将其更改为“e 的所有父级都包含在路径中”。

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

于 2018-05-22T20:53:47.420 回答