|| 聚合函数 - Cypher 手册 - Neo4j 文档

聚合函数

聚合函数对一组值执行计算,并返回单个值。聚合可以针对所有匹配的路径进行计算,也可以通过引入分组键进一步细分。

要详细了解 Cypher® 如何处理对零行执行的聚合,请参阅Neo4j 知识库 → 理解对零行的聚合。

示例图

以下图用于下面的示例

graph aggregating functions

要重新创建该图,请针对空的 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()

详情

语法

avg(input)

描述

返回一组 INTEGER、FLOAT 或 DURATION 值的平均值。

参数

名称

类型

描述

input

INTEGER | FLOAT | DURATION

聚合以形成平均值的值。

返回

INTEGER | FLOAT | DURATION

注意事项

任何 null 值都将从计算中排除。

avg(null) 返回 null。

示例 1. avg() - 数值
查询
MATCH (p:Person)
RETURN avg(p.age)

返回属性 age 中所有值的平均值

结果
avg(p.age)

61.8

行数: 1

示例 2. avg() - 持续时间值
查询
UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN avg(dur)

返回两个提供的 DURATION 值的平均值

结果
avg(dur)

P1DT2H22.5S

行数: 1

collect()

详情

语法

collect(input)

描述

返回一个包含表达式返回值的列表。

参数

名称

类型

描述

input

ANY

聚合到列表中的值。

返回

LIST<ANY>

注意事项

任何 null 值都将被忽略,不会添加到列表中。

collect(null) 返回一个空列表。

示例 3. collect()
查询
MATCH (p:Person)
RETURN collect(p.age)

所有值都被收集并以单个列表返回

结果
collect(p.age)

[58, 70, 55, 55, 71]

行数: 1

count()

详情

语法

count(input)

描述

返回值的数量或行数。

参数

名称

类型

描述

input

ANY

要聚合的值。

返回

INTEGER

注意事项

count(*) 包括返回 null 的行。

count(input) 忽略 null 值。

count(null) 返回 0。

Neo4j 维护一个事务计数存储用于保存计数元数据,这可以显著提高使用 count() 函数的查询速度。有关计数存储的更多信息,请参阅Neo4j 知识库 → 使用计数存储进行快速计数。

使用 count(*) 返回节点数量

函数 count(*) 可用于返回节点数量;例如,连接到节点 n 的节点数量。

示例 4. count()
查询
MATCH (p:Person {name: 'Keanu Reeves'})-->(x)
RETURN labels(p), p.age, count(*)

返回起始节点 Keanu Reeves 的标签、age 属性以及与其相关的节点数量

结果
labels(p) p.age count(*)

["Person"]

58

4

行数: 1

使用 count(*) 按关系类型分组和计数

函数 count(*) 可用于对匹配关系类型进行分组并返回类型数量。

示例 5. count()
查询
MATCH (p:Person {name: 'Keanu Reeves'})-[r]->()
RETURN type(r), count(*)

匹配关系类型被分组并返回关系类型的分组计数

结果
type(r) count(*)

"ACTED_IN"

1

"KNOWS"

3

行数: 2

计数非 null 值

除了简单地使用 count(*) 返回行数外,函数 count(expression) 还可以用于返回表达式返回的非 null 值的数量。

示例 6. count()
查询
MATCH (p:Person)
RETURN count(p.age)

返回带有标签 Person 和属性 age 的节点数量:(要计算总和,请使用 sum(n.age))

结果
count(p.age)

5

行数: 1

计数时包含和不包含重复项

count 函数的默认行为是计算所有匹配结果,包括重复项。为避免计算重复项,请使用 DISTINCT 关键字。

自 Neo4j 5.15 起,聚合函数也可以使用 ALL 关键字。这将计算所有结果,包括重复项,功能上与不使用 DISTINCT 关键字相同。ALL 关键字作为 Cypher GQL 合规性的一部分引入。

此示例尝试查找 Keanu Reeves 的所有朋友的朋友并计数。它展示了使用 ALL 和 DISTINCT 关键字的行为

示例 7. count()
查询
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)

"Guy Pearce"

2

2

1

行数: 1

max()

详情

语法

max(input)

描述

返回一组值中的最大值。

参数

名称

类型

描述

input

ANY

要聚合的值。

返回

ANY

注意事项

任何 null 值都将从计算中排除。

在混合集中,任何数值始终被视为高于任何 STRING 值,任何 STRING 值始终被视为高于任何 LIST<ANY>。

列表按字典顺序比较,即列表元素从列表的开头到结尾按升序逐对比较。

max(null) 返回 null。

示例 8. max()
查询
UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN max(val)

返回混合集中所有值中的最高值——在本例中为数值 1

结果
max(val)

1

行数: 1

值 '99' (一个 STRING) 被认为是低于 1 (一个 INTEGER) 的值,因为 '99' 是一个 STRING。

示例 9. max()
查询
UNWIND [[1, 'a', 89], [1, 2]] AS val
RETURN max(val)

返回集合中所有列表中的最高值——在本例中为列表 [1, 2]——因为数字 2 被认为是高于字符串 'a' 的值,即使列表 [1, 'a', 89] 包含更多元素。

结果
max(val)

[1,2]

行数: 1

示例 10. max()
查询
MATCH (p:Person)
RETURN max(p.age)

返回属性 age 中所有值的最高值

结果
max(p.age)

71

行数: 1

min()

详情

语法

min(input)

描述

返回一组值中的最小值。

参数

名称

类型

描述

input

ANY

要聚合的值。

返回

ANY

注意事项

任何 null 值都将从计算中排除。

在混合集中,任何 STRING 值始终被视为低于任何数值,任何 LIST<ANY> 始终被视为低于任何 STRING。

列表按字典顺序比较,即列表元素从列表的开头到结尾按升序逐对比较。

min(null) 返回 null。

示例 11. 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"

行数: 1

示例 12. min()
查询
UNWIND ['d', [1, 2], ['a', 'c', 23]] AS val
RETURN min(val)

返回集合中所有值中的最低值——在本例中为列表 ['a', 'c', 23]——因为 (i) 这两个列表被认为是低于 STRING "d" 的值,并且 (ii) STRING "a" 被认为是低于数值 1 的值。

结果
min(val)

["a","c",23]

行数: 1

示例 13. min()
查询
MATCH (p:Person)
RETURN min(p.age)

返回属性 age 中所有值的最低值

结果
min(p.age)

55

行数: 1

percentileCont()

详情

语法

percentileCont(input, percentile)

描述

使用线性插值法返回一组值的分位数。

参数

名称

类型

描述

input

FLOAT

要聚合的值。

percentile

FLOAT

介于 0.0 和 1.0 之间的分位数。

返回

FLOAT

注意事项

任何 null 值都将从计算中排除。

percentileCont(null, percentile) 返回 null。

示例 14. percentileCont()
查询
MATCH (p:Person)
RETURN percentileCont(p.age, 0.4)

返回属性 age 中值的第 40 个分位数,通过加权平均计算

结果
percentileCont(p.age, 0.4)

56.8

行数: 1

percentileDisc()

详情

语法

percentileDisc(input, percentile)

描述

使用四舍五入法返回一组值中给定分位数最接近的 INTEGER 或 FLOAT 值。

参数

名称

类型

描述

input

INTEGER | FLOAT

要聚合的值。

percentile

FLOAT

介于 0.0 和 1.0 之间的分位数。

返回

INTEGER | FLOAT

注意事项

任何 null 值都将从计算中排除。

percentileDisc(null, percentile) 返回 null。

示例 15. percentileDisc()
查询
MATCH (p:Person)
RETURN percentileDisc(p.age, 0.5)

返回属性 age 中值的第 50 个分位数

结果
percentileDisc(p.age, 0.5)

58

行数: 1

stDev()

详情

语法

stDev(input)

描述

返回给定值在一组人口样本中的标准差。

参数

名称

类型

描述

input

FLOAT

用于计算标准差的值。

返回

FLOAT

注意事项

任何 null 值都将从计算中排除。

stDev(null) 返回 0。

示例 16. stDev()
查询
MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDev(p.age)

返回属性 age 中值的标准差

结果
stDev(p.age)

7.937253933193772

行数: 1

stDevP()

详情

语法

stDevP(input)

描述

返回给定值在整个人口中的标准差。

参数

名称

类型

描述

input

FLOAT

用于计算人口标准差的值。

返回

FLOAT

注意事项

任何 null 值都将从计算中排除。

stDevP(null) 返回 0。

示例 17. stDevP()
查询
MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDevP(p.age)

返回属性 age 中值的人口标准差

结果
stDevP(p.age)

6.48074069840786

行数: 1

sum()

详情

语法

sum(input)

描述

返回一组 INTEGER、FLOAT 或 DURATION 值的总和

参数

名称

类型

描述

input

INTEGER | FLOAT | DURATION

要聚合的值。

返回

INTEGER | FLOAT | DURATION

注意事项

任何 null 值都将从计算中排除。

sum(null) 返回 0。

示例 18. sum() - 数值
查询
MATCH (p:Person)
RETURN sum(p.age)

返回属性 age 中所有值的总和

结果
sum(p.age)

309

行数: 1

示例 19. sum() - 持续时间值
查询
UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN sum(dur)

返回两个提供的持续时间值的总和

结果
sum(dur)

P2DT4H45S

行数: 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 子句中。

示例

示例 20. 没有分组键的简单聚合
查询
MATCH (p:Person)
RETURN max(p.age)
结果
max(p.age)

71

行数: 1

示例 21. 聚合与常量的加法,没有分组键
查询
MATCH (p:Person)
RETURN max(p.age) + 1
结果
max(p.age) + 1

72

行数: 1

示例 22. 属性访问与聚合的减法

注意 p 是一个分组键

查询
MATCH (p:Person{name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p, p.age - max(f.age)
结果
p p.age - max(f.age)

{{"name":"Keanu Reeves","age":58}}

-13

行数: 1

示例 23. 属性访问与聚合的减法。

注意 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)

58

-13

行数: 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)

116

45

行数: 1

聚合表达式的规则

为了使聚合表达式能够正确计算由分组键形成的桶,它们必须满足一些要求。具体来说,聚合表达式中的每个子表达式必须是以下之一:

  • 一个聚合函数,例如 sum(x.a)。

  • 一个常量,例如 0.1。

  • 一个参数,例如 $param。

  • 一个分组键,例如 RETURN a, count(*) 中的 a。

  • 一个局部变量,例如 count(*) + size([ x IN range(1, 10) | x ]) 中的 x。

  • 一个子表达式,其所有操作数都必须在聚合表达式中允许。

© . This site is unofficial and not affiliated with Neo4j, Inc.