Cypher:更新特定节点列表中所有节点对之间的关系

0 投票
1 回答
507 浏览
提问于 2025-04-18 14:46

我正在使用Neo4j,对如何在Cypher中进行一些查询以保持高性能有些担心。

我有一个图,里面的节点都有一个标签叫“Thing”。每个节点都有一个属性pk(整数类型)。

现在,我有一个像[123, 34, 125]这样的pk列表,我想创建/更新(如果已经存在的话)所有可能的节点对之间的关系。

比如说要创建(123, 34)、(123, 125)、(34, 125)这样的关系,并且对于每一对节点之间的关系r.weight = 0(如果是新创建的关系),或者r.weight += 1(如果关系已经存在)。

目前,我在Python中使用itertools.combinations(pks, 2)来生成组合,然后对每一对c1, c2进行处理:

'MATCH (c1:Thing {pk: %(c1_pk)s}), (c2:Thing {pk: %(c2_pk)s}) ' \
'CREATE UNIQUE c1-[r:KNOWS]-c2 ' \
'SET r.weight=coalesce(r.weight, 0)+1 RETURN c1, r.weight, c2' % {'c1_pk': c1_pk,
                                                                  'c2_pk': c2_pk}

但是我不喜欢对每一对都调用查询,因为当pk列表很长时,性能会很差,因为组合和查询的次数是length(pks)*(length(pks)-1)。

我该怎么做呢?

编辑: 现在大约有15000个“Thing”节点,并且这个数量将始终保持不变。 还有一个约束条件是pk属性必须唯一(t:Thing t.pk是唯一的)。

1 个回答

0

你在创建这些成对关系时没有任何限制,所以你想用笛卡尔积的方式来做。如果节点很多,这样会很慢。

不过,我看到你查询中的一个错误是,你试图创建每个关系两次;比如说你想从 X 指向 Y。你首先创建了 X 指向 Y,然后又创建了 Y 指向 X。

你可以通过只创建一次来把这个数量减半,像这样:

MATCH (c1:Thing {pk: %(c1_pk)s}), (c2:Thing {pk: %(c2_pk)s}) 
CREATE UNIQUE c1-[r:KNOWS]-c2 
SET r.weight=coalesce(r.weight, 0)+1 RETURN c1, r.weight, c2' % {'c1_pk': c1_pk,
                                                                  'c2_pk': c2_pk}
WHERE c1.id < c2.id

注意我们是按 ID 来排序节点的。因为它们的 ID 都不一样,所以你只会做 X 指向 Y,而不会做 Y 指向 X。

这样,你的整体处理过程就从 length(pks)*length(pks)-1 变成了: ( length(pks)*length(pks)-1 ) / 2。

不过,想要避免的事情是,你正在做的事情是 O(n^2) 的复杂度。

撰写回答