如何将集合分组为数据集上的运算符/方法?

Posted

技术标签:

【中文标题】如何将集合分组为数据集上的运算符/方法?【英文标题】:How to GROUPING SETS as operator/method on Dataset? 【发布时间】:2017-04-16 20:39:36 【问题描述】:

spark scala 中没有函数级别的 grouping_sets 支持吗?

我不知道这个补丁是否应用于 master https://github.com/apache/spark/pull/5080

我想通过 scala dataframe api 做这种查询。

GROUP BY expression list GROUPING SETS(expression list2)

cuberollup functions 在 Dataset API 中可用,但找不到分组集。为什么?

【问题讨论】:

【参考方案1】:

我想通过 scala dataframe api 做这种查询。

tl;dr 在 Spark 2.1.0 之前这是不可能的。目前没有计划将此类运算符添加到 Dataset API。

Spark SQL 支持以下所谓的多维聚合运算符

rollup运营商 cube运营商 GROUPING SETS 子句(仅在 SQL 模式下) grouping()grouping_id() 函数

注意: GROUPING SETS 仅在 SQL 模式下可用。 Dataset API 不支持。

分组集

val sales = Seq(
  ("Warsaw", 2016, 100),
  ("Warsaw", 2017, 200),
  ("Boston", 2015, 50),
  ("Boston", 2016, 150),
  ("Toronto", 2017, 50)
).toDF("city", "year", "amount")
sales.createOrReplaceTempView("sales")

// equivalent to rollup("city", "year")
val q = sql("""
  SELECT city, year, sum(amount) as amount
  FROM sales
  GROUP BY city, year
  GROUPING SETS ((city, year), (city), ())
  ORDER BY city DESC NULLS LAST, year ASC NULLS LAST
  """)

scala> q.show
+-------+----+------+
|   city|year|amount|
+-------+----+------+
| Warsaw|2016|   100|
| Warsaw|2017|   200|
| Warsaw|null|   300|
|Toronto|2017|    50|
|Toronto|null|    50|
| Boston|2015|    50|
| Boston|2016|   150|
| Boston|null|   200|
|   null|null|   550|  <-- grand total across all cities and years
+-------+----+------+
// equivalent to cube("city", "year")
// note the additional (year) grouping set
val q = sql("""
  SELECT city, year, sum(amount) as amount
  FROM sales
  GROUP BY city, year
  GROUPING SETS ((city, year), (city), (year), ())
  ORDER BY city DESC NULLS LAST, year ASC NULLS LAST
  """)

scala> q.show
+-------+----+------+
|   city|year|amount|
+-------+----+------+
| Warsaw|2016|   100|
| Warsaw|2017|   200|
| Warsaw|null|   300|
|Toronto|2017|    50|
|Toronto|null|    50|
| Boston|2015|    50|
| Boston|2016|   150|
| Boston|null|   200|
|   null|2015|    50|  <-- total across all cities in 2015
|   null|2016|   250|  <-- total across all cities in 2016
|   null|2017|   250|  <-- total across all cities in 2017
|   null|null|   550|
+-------+----+------+

如果结果表的列中的值为null,则不一定意味着该列已在该行上聚合。如果该列在原始表中有nulls,则聚合表中的null 值可能仅代表原始表中的null 值。使用grouping 函数检查列是否聚合在特定行上。

【讨论】:

如何查询报告,例如我想在 2015 年跨城市获取总数。我是否需要将所有其他列设为空。例如,从表中选择金额,其中 year=2015 且城市为空,并且每隔一列为空 @PushpendraJaiswal 这正是我的建议。 如果结果表的列中的值为空,则不一定意味着该列是在该行上聚合的。如果该列在原始表中有空值,则聚合表中的空值可能仅表示原始表中的空值。您可以使用grouping 函数检查该列是否在特定行上聚合。【参考方案2】:

Spark 支持GROUPING SETS。你可以在这里找到相应的测试:

https://github.com/apache/spark/blob/5b7d403c1819c32a6a5b87d470f8de1a8ad7a987/sql/core/src/test/resources/sql-tests/inputs/group-analytics.sql#L25-L28

【讨论】:

但是dataframe函数api怎么样。我找不到它。 没有。它仅在 SQL 中可用。

以上是关于如何将集合分组为数据集上的运算符/方法?的主要内容,如果未能解决你的问题,请参考以下文章

Scala 运算符和集合转换操作示例

Spark 两种方法计算分组取Top N

Impala 上的多维数据集运算符

数据聚合与分组运算

表的集合操作

Python数据聚合和分组运算-Data Aggregation