聚合函数
聚合函数对一组值执行计算,并返回单个值。聚合可以针对所有匹配的路径进行计算,也可以通过引入 分组键 进一步划分。
要详细了解 Cypher® 如何处理对零行执行的聚合,请参阅 Neo4j 知识库 → 了解对零行的聚合。 |
示例图
以下图表用于下面的示例
要重新创建该图,请对一个空的 Neo4j 数据库运行以下查询
CREATE
(keanu:Person {name: 'Keanu Reeves', age: 58}),
(liam:Person {name: 'Liam Neeson', age: 70}),
(carrie:Person {name: 'Carrie Anne Moss', age: 55}),
(guy:Person {name: 'Guy Pearce', age: 55}),
(kathryn:Person {name: 'Kathryn Bigelow', age: 71}),
(speed:Movie {title: 'Speed'}),
(keanu)-[:ACTED_IN]->(speed),
(keanu)-[:KNOWS]->(carrie),
(keanu)-[:KNOWS]->(liam),
(keanu)-[:KNOWS]->(kathryn),
(carrie)-[:KNOWS]->(guy),
(liam)-[:KNOWS]->(guy)
avg()
语法 |
|
||
描述 |
返回一组 |
||
参数 |
名称 |
类型 |
描述 |
|
|
聚合以形成平均值的值。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
RETURN avg(p.age)
返回属性 age
中所有值的平均值
avg(p.age) |
---|
|
行:1 |
UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN avg(dur)
返回两个提供的 DURATION
值的平均值
avg(dur) |
---|
|
行:1 |
collect()
语法 |
|
||
描述 |
返回一个包含表达式返回的值的列表。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
聚合到列表中的值。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
RETURN collect(p.age)
所有值都被收集并返回到一个列表中
collect(p.age) |
---|
|
行:1 |
count()
语法 |
|
||
描述 |
返回值或行的数量。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
|
|
|
Neo4j 维护一个事务计数存储,用于保存计数元数据,这可以显着提高使用 |
使用 count(*)
返回节点数量
函数 count(*)
可用于返回节点数量;例如,与节点 n
相连的节点数量。
MATCH (p:Person {name: 'Keanu Reeves'})-->(x)
RETURN labels(p), p.age, count(*)
返回起始节点 Keanu Reeves
的标签和 age
属性以及与其相关的节点数量
labels(p) | p.age | count(*) |
---|---|---|
|
|
|
行:1 |
55
3
"ACTED_IN"
2
MATCH (p:Person)
RETURN count(p.age)
4
Rows: 2 |
---|
|
行:1 |
对非 null
值进行计数
函数 count(expression)
可以用来返回表达式返回的非 null
值的数量,而不是简单地使用 count(*)
返回行数。
示例 6. count()
返回具有标签 Person
且具有属性 age
的节点数量:(要计算总和,请使用 sum(n.age)
)
MATCH (p:Person)-->(friend:Person)-->(friendOfFriend:Person)
WHERE p.name = 'Keanu Reeves'
RETURN friendOfFriend.name, count(friendOfFriend), count(ALL friendOfFriend), count(DISTINCT friendOfFriend)
3
有无重复计数 | count 函数的默认行为是计算所有匹配的结果,包括重复项。要避免计数重复项,请使用 DISTINCT 关键字。 |
从 Neo4j 5.15 开始,还可以将 ALL 关键字与聚合函数一起使用。这将计算所有结果,包括重复项,在功能上等同于不使用 DISTINCT 关键字。ALL 关键字是在 Cypher 的 GQL 符合性 中引入的。 |
此示例尝试查找 Keanu Reeves 的所有朋友的朋友,并对他们进行计数。它展示了使用 ALL 和 DISTINCT 关键字的行为 |
---|---|---|---|
|
|
|
|
节点 Carrie Anne Moss
和 Liam Neeson
都与 Guy Pearce
存在出站 KNOWS
关系。因此,Guy Pearce
节点在不使用 DISTINCT
的情况下会被计算两次。
语法 |
|
||
描述 |
count(friendOfFriend) |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
任何 |
count(ALL friendOfFriend) |
count(DISTINCT friendOfFriend) |
"Guy Pearce" |
UNWIND [[1, 'a', 89], [1, 2]] AS val
RETURN max(val)
在集合中返回所有列表中最高的列表 - 在这种情况下是列表 [1, 2]
- 因为数字 2
被认为比 STRING
'a'
更高,即使列表 [1, 'a', 89]
包含更多元素。
1 |
---|
|
行:1 |
MATCH (p:Person)
RETURN max(p.age)
返回属性 age
中所有值中最高的那个。
max(p.age) |
---|
|
行:1 |
min()
语法 |
|
||
描述 |
返回一组值中的最小值。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
任何 |
在混合集合中,任何 |
count(DISTINCT friendOfFriend) |
|
UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN min(val)
返回混合集合中所有值中最小的那个 - 在这种情况下是 STRING
值 "1"
-。注意,(数值)值 0.2
乍一看似乎是列表中最小的值,但它被认为比 "1"
更高,因为后者是 STRING
。
min(val) |
---|
|
行:1 |
UNWIND ['d', [1, 2], ['a', 'c', 23]] AS val
RETURN min(val)
返回集合中所有值中最小的那个 - 在这种情况下是列表 ['a', 'c', 23]
-,因为 (i) 两个列表被认为比 STRING
"d"
值低,并且 (ii) STRING
"a"
被认为比数值 1
值低。
min(val) |
---|
|
行:1 |
MATCH (p:Person)
RETURN min(p.age)
返回属性 age
中所有值中最小的那个。
min(p.age) |
---|
|
行:1 |
percentileCont()
语法 |
|
||
描述 |
使用线性插值返回一组值中某个值的百分位数。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
|
|
介于 0.0 和 1.0 之间的百分位数。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
RETURN percentileCont(p.age, 0.4)
返回属性 age
中值的第 40 个百分位数,使用加权平均值计算。
percentileCont(p.age, 0.4) |
---|
|
行:1 |
percentileDisc()
语法 |
|
||
描述 |
使用舍入方法返回一组值中最近的 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
|
|
介于 0.0 和 1.0 之间的百分位数。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
RETURN percentileDisc(p.age, 0.5)
返回属性 age
中值的第 50 个百分位数。
percentileDisc(p.age, 0.5) |
---|
|
行:1 |
stDev()
语法 |
|
||
描述 |
返回给定值在一组中对于总体样本的标准差。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要计算标准差的值。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDev(p.age)
返回属性 age
中值的标准差。
stDev(p.age) |
---|
|
行:1 |
stDevP()
语法 |
|
||
描述 |
返回给定值在一组中对于整个总体的标准差。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要计算总体标准差的值。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDevP(p.age)
返回属性 age
中值的总体标准差。
stDevP(p.age) |
---|
|
行:1 |
sum()
语法 |
|
||
描述 |
返回一组 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
任何 |
|
MATCH (p:Person)
RETURN sum(p.age)
返回属性 age
中所有值的总和。
sum(p.age) |
---|
|
行:1 |
UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN sum(dur)
返回两个提供的持续时间的总和。
sum(dur) |
---|
|
行:1 |
聚合表达式和分组键
聚合表达式是包含一个或多个聚合函数的表达式。一个简单的聚合表达式包含一个聚合函数。例如,sum(x.a)
是一个聚合表达式,它只包含聚合函数 sum( )
,其中 x.a
是它的参数。聚合表达式也可以更复杂,其中一个或多个聚合函数的结果是其他表达式的输入参数。例如,0.1 * (sum(x.a) / count(x.b))
是一个聚合表达式,它包含两个聚合函数,sum( )
,其中 x.a
是它的参数,以及 count( )
,其中 x.b
是它的参数。两者都是除法表达式的输入参数。
分组键是非聚合表达式,用于对输入聚合函数的值进行分组。例如,给定以下查询,其中包含两个返回表达式,n
和 count(*)
RETURN n, count(*)
第一个,n
不是聚合函数,因此它将是分组键。第二个,count(*)
是一个聚合函数。匹配的路径将被划分为不同的桶,具体取决于分组键。然后,聚合函数将在这些桶上运行,计算每个桶的聚合值。
聚合函数的输入表达式可以包含任何表达式,包括非分组键表达式。但是,并非所有表达式都可以与聚合函数组合。下面的示例将抛出错误,因为 n.x
(不是分组键)与聚合函数 count(*)
组合在一起。
RETURN n.x + count(*)
要使用聚合函数对结果集进行排序,必须在 RETURN
子句后面的 ORDER BY
子句中包含聚合。
示例
MATCH (p:Person)
RETURN max(p.age)
max(p.age) |
---|
|
行:1 |
MATCH (p:Person)
RETURN max(p.age) + 1
max(p.age) + 1 |
---|
|
行:1 |
注意 p
是一个分组键
MATCH (p:Person{name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p, p.age - max(f.age)
p | p.age - max(f.age) |
---|---|
|
|
行:1 |
注意 p.age
是一个分组键
MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age, p.age - max(f.age)
p.age | p.age - max(f.age) |
---|---|
|
|
行:1 |
分组键本身可以是复杂的表达式。为了更好地查询可读性,Cypher 仅在聚合表达式中将子表达式识别为分组键,如果分组键是以下之一:
-
变量 - 例如
RETURN p, p.age - max(f.age)
中的p
。 -
属性访问 - 例如
RETURN p.age, p.age - max(f.age)
中的p.age
。 -
映射访问 - 例如
WITH {name:'Keanu Reeves', age:58} AS p RETURN p.age, p.age - max(p.age)
中的p.age
。
如果需要更复杂的分组键作为聚合表达式的操作数,则始终可以使用 WITH
预先投影它们。
使用属性 p.age
将会抛出异常,因为 p.age
不是分组键。因此,它不能用于包含聚合函数的表达式中。因此,以下两个查询将返回相同的错误消息
MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age - max(f.age)
MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age + p.age, p.age + p.age - max(f.age)
Aggregation column contains implicit grouping expressions. For example, in 'RETURN n.a, n.a + n.b + count(*)' the aggregation expression 'n.a + n.b + count(*)' includes the implicit grouping key 'n.b'. It may be possible to rewrite the query by extracting these grouping/aggregation expressions into a preceding WITH clause. Illegal expression(s): n.age
但是,如果将后面的查询改写为以下形式,则可以正常工作
MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
WITH p.age + p.age AS groupingKey, f
RETURN groupingKey, groupingKey - max(f.age)
分组键 | 分组键 - max(f.age) |
---|---|
|
|
行:1 |