首页 > 解决方案 > Neo4j Cypher 聚合函数在 WITH 子句中的变化

问题描述

我是 Neo4j 的新手,平均功能有问题。

我有一个银行账户(节点)和它们之间的支付(关系)的测试数据库。

我想计算每对账户之间的平均付款(即 A&B 之间、A&C 之间、B&C 之间等),然后找到任何高于平均值 50 美元的付款。

我的代码如下所示:

MATCH (a)-[r:Payment]-(b)
WITH a, b, AVG(ToFloat(r.Amount)) AS Average, ToFloat(r.Amount) as Amount
WHERE Amount-Average>50
RETURN a, b, Amount-Average AS Difference

如果我只在 WITH 子句中留下 a 和 Average,它似乎可以正确计算平均值,但如果我添加其他任何内容(r 或 r.Amount 子句),那么 Average 函数输出会发生变化,并且只返回相同的值值作为“金额”(因此它会将每个关系的“差异”计算为 0)。

难道是我匹配节点和关系的方式没有正确找到每对帐户之间的关系然后对它们进行平均,这会导致错误?

提前致谢!

标签: neo4jcypheraggregate-functions

解决方案


这是 Cypher 在执行聚合时隐式分组的结果。分组键(分组发生的上下文)是隐式的,由 WITH 或 RETURN 子句中存在的非聚合变量形成。

这就是为什么当您包含rorr.amount时,输出会发生变化,因为您将计算关于相同关系或相同数量的平均值(单个值的平均值就是该值)。

由于您要根据平均值评估和过滤节点之间的所有金额,因此您应该在取平均值时收集金额,然后过滤/转换内容以供返回。

此外,您需要包含一些过滤ab确保不返回镜像结果(相同节点的结果相同,但a交换的节点除外b),因此我们将对节点 ID 使用限制确保仅在一个方向上订购:

MATCH (a)-[r:Payment]-(b)
WHERE id(a) < id(b) // ensure we don't get mirrored results
WITH a, b, AVG(ToFloat(r.Amount)) AS Average, collect(ToFloat(r.Amount)) as Amounts
WITH a, b, [amt in Amounts WHERE amt-Average > 50 | amt - Average] as Differences
RETURN a, b, Differences

如果您希望每一行都有单独的结果,那么您可以Differences在返回之前 UNWIND 列表。


推荐阅读