关于 YMatrix
部署数据库
使用数据库
管理集群
最佳实践
高级功能
高级查询
联邦查询
Grafana 监控
备份恢复
灾难恢复
图数据库
管理手册
性能调优
故障诊断
工具指南
系统配置参数
SQL 参考
通常,聚合 aggr(expr) 会处理传入记录中找到的每个聚合键的所有匹配行(键使用等价性进行比较)。
在常规聚合(即 aggr(expr) 形式)中,聚合值列表是从候选值列表中移除所有 null 值后的列表。
注意! 在 YMatrix AGE 中,聚合的结果是无序的。如果想要聚合的结构有序,则需要在cypher 子句外面给cypher 子查询排序,cypher内的 order by 无用(只能保证在Segments结果有序,不能保证全局有序)。 Example:
SELECT * FROM cypher('graph_name', $$> /* aggr(expr) */>$$) AS (grouping_key agtype) **ORDER BY grouping_key**;
SELECT * FROM cypher('graph_name', $$
CREATE (a:Person {name: 'A', age: 13}),
(b:Person {name: 'B', age: 33, eyes: "blue"}),
(c:Person {name: 'C', age: 44, eyes: "blue"}),
(d1:Person {name: 'D', eyes: "brown"}),
(d2:Person {name: 'D'}),
(a)-[:KNOWS]->(b),
(a)-[:KNOWS]->(c),
(a)-[:KNOWS]->(d1),
(b)-[:KNOWS]->(d2),
(c)-[:KNOWS]->(d2)
$$) as (a agtype);
为了计算聚合数据,Cypher 提供了聚合功能,类似于 SQL 的 GROUP BY。
聚合函数接受一组值并计算它们的聚合值。例如 avg() 计算多个数值的平均值,或 min() 查找一组值中最小的数值或字符串值。当我们说聚合函数对一组值进行操作时,我们指的是将内部表达式(如 n.age)应用于同一聚合组内所有记录的结果。
聚合可以在所有匹配的子图上计算,也可以通过引入分组键进一步划分。这些是非聚合表达式,用于对进入聚合函数的值进行分组。
假设我们有以下 return 语句:
SELECT * FROM cypher('graph_name', $$
MATCH (v:Person)
RETURN v.name, count(*)
$$) as (grouping_key agtype, count agtype);
| count | key |
|---|---|
| "A" | 1 |
| "B" | 1 |
| "C" | 1 |
| "D" | 2 |
| 1 row |
我们有两个返回表达式:grouping_key 和 count(*)。第一个 grouping_key 不是聚合函数,因此它将成为分组键。后者 count(*) 是聚合表达式。匹配的子图将根据分组键被划分到不同的桶中。然后聚合函数将在这些桶上运行,为每个桶计算一个聚合值。
在 distinct 聚合(即 aggr(DISTINCT expr) 形式)中,聚合值列表是从候选值列表中移除所有 null 值后的列表。此外,在 distinct 聚合中,所有等价候选值中只有一个被包含在聚合值列表中,即在等价性下的重复值被移除。
DISTINCT 运算符与聚合配合使用。它用于在通过聚合函数运行之前使所有值唯一。
SELECT *
FROM cypher('graph_name', $$
MATCH (v:Person)
RETURN count(DISTINCT v.eyes), count(v.eyes)
$$) as (distinct_eyes agtype, eyes agtype);
| distinct_eyes | eyes |
|---|---|
| 2 | 3 |
| 1 row |
不要求用户为查询指定分组键的这一特性允许 Cypher 在确定分组键时存在歧义。
数据准备
SELECT * FROM cypher('graph_name', $$
CREATE (:L {a: 1, b: 2, c: 3}),
(:L {a: 2, b: 3, c: 1}),
(:L {a: 3, b: 1, c: 2})
$$) as (a agtype);
AGE 对此问题的解决方案是不允许 WITH 或 RETURN 列将聚合函数与未在同一 WITH 或 RETURN 子句的另一列中显式列出的变量组合。
查询:
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN x.a + count(*) + x.b + count(*) + x.c
$$) as (a agtype);
结果:
ERROR: "x" must be either part of an explicitly listed key or used inside an aggregate function
LINE 3: RETURN x.a + count(*) + x.b + count(*) + x.c
在 AGE 中,不包含聚合函数的列被视为该 WITH 或 RETURN 子句的分组键。
对于上述查询,用户可以用几种方式重写查询以返回结果:
查询:
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN (x.a + x.b + x.c) + count(*) + count(*), x.a + x.b + x.c
$$) as (count agtype, key agtype);
x.a + x.b + x.c 是分组键。以这种方式创建的分组键必须包含括号。
结果:
| count | key |
|---|---|
| 12 | 6 |
| 1 row |
查询:
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN x.a + count(*) + x.b + count(*) + x.c, x.a, x.b, x.c
$$) as (count agtype, a agtype, b agtype, c agtype);
x.a、x.b 和 x.c 将被视为不同的分组键。
结果:
| count | a | b | c |
|---|---|---|---|
| 8 | 3 | 1 | 2 |
| 8 | 2 | 3 | 1 |
| 8 | 1 | 2 | 3 |
| 3 rows |
或者,分组键可以是顶点或边,然后可以指定顶点或边的任何属性,而无需在 WITH 或 RETURN 列中显式声明。
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN count(*) + count(*) + x.a + x.b + x.c, x
$$) as (count agtype, key agtype);
结果将按 x 分组,因为可以安全地假设属性对于分组的明确性是不必要的。
如果分组键对于查询输出是不必要的,可以在 WITH 子句中进行聚合,然后将信息传递给 RETURN 子句。
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
WITH count(*) + count(*) + x.a + x.b + x.c as column, x
RETURN column
$$) as (a agtype);
结果:
| a |
|---|
| 8 |
| 8 |
| 8 |
| 3 rows |