聚合函数
聚合函数对一组值执行计算,并返回单个值。聚合可以针对所有匹配的路径进行计算,也可以通过引入分组键进一步细分。
要详细了解 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 |
使用 count(*)
按关系类型分组和计数
函数 count(*)
可用于对匹配关系类型进行分组并返回类型数量。
MATCH (p:Person {name: 'Keanu Reeves'})-[r]->()
RETURN type(r), count(*)
匹配关系类型被分组并返回关系类型的分组计数
type(r) | count(*) |
---|---|
|
|
|
|
行数: 2 |
计数非 null
值
除了简单地使用 count(*)
返回行数外,函数 count(expression)
还可以用于返回表达式返回的非 null
值的数量。
MATCH (p:Person)
RETURN count(p.age)
返回带有标签 Person
和属性 age
的节点数量:(要计算总和,请使用 sum(n.age)
)
count(p.age) |
---|
|
行数: 1 |
计数时包含和不包含重复项
count
函数的默认行为是计算所有匹配结果,包括重复项。为避免计算重复项,请使用 DISTINCT
关键字。
自 Neo4j 5.15 起,聚合函数也可以使用 ALL
关键字。这将计算所有结果,包括重复项,功能上与不使用 DISTINCT
关键字相同。ALL
关键字作为 Cypher GQL 合规性的一部分引入。
此示例尝试查找 Keanu Reeves
的所有朋友的朋友并计数。它展示了使用 ALL
和 DISTINCT
关键字的行为
MATCH (p:Person)-->(friend:Person)-->(friendOfFriend:Person)
WHERE p.name = 'Keanu Reeves'
RETURN friendOfFriend.name, count(friendOfFriend), count(ALL friendOfFriend), count(DISTINCT friendOfFriend)
节点 Carrie Anne Moss
和 Liam Neeson
都与 Guy Pearce
有一个传出的 KNOWS
关系。因此,当不使用 DISTINCT
时,Guy Pearce
节点将被计数两次。
friendOfFriend.name | count(friendOfFriend) | count(ALL friendOfFriend) | count(DISTINCT friendOfFriend) |
---|---|---|---|
|
|
|
|
行数: 1 |
max()
语法 |
|
||
描述 |
返回一组值中的最大值。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
任何 |
在混合集中,任何数值始终被视为高于任何 |
列表按字典顺序比较,即列表元素从列表的开头到结尾按升序逐对比较。 |
|
UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN max(val)
返回混合集中所有值中的最高值——在本例中为数值 1
max(val) |
---|
|
行数: 1 |
值 |
UNWIND [[1, 'a', 89], [1, 2]] AS val
RETURN max(val)
返回集合中所有列表中的最高值——在本例中为列表 [1, 2]
——因为数字 2
被认为是高于字符串 'a'
的值,即使列表 [1, 'a', 89]
包含更多元素。
max(val) |
---|
|
行数: 1 |
MATCH (p:Person)
RETURN max(p.age)
返回属性 age
中所有值的最高值
max(p.age) |
---|
|
行数: 1 |
min()
语法 |
|
||
描述 |
返回一组值中的最小值。 |
||
参数 |
名称 |
类型 |
描述 |
|
|
要聚合的值。 |
|
返回 |
|
任何 |
在混合集中,任何 |
列表按字典顺序比较,即列表元素从列表的开头到结尾按升序逐对比较。 |
|
UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN min(val)
返回混合集中所有值中的最低值——在本例中为 STRING
值 "1"
。请注意,数值 0.2
,乍一看可能是列表中最低的值,但由于 "1"
是 STRING
,因此 0.2 被认为是高于 "1"
的值。
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)
groupingKey | groupingKey - max(f.age) |
---|---|
|
|
行数: 1 |