我找不到有关差异的任何详细文档。
我确实注意到了差异,因为在交换cube
和groupBy
函数调用时,我得到的结果不同。我注意到对于使用cube
的结果,我在以前使用groupBy
的表达式上得到了很多 null 值。
这些不打算以相同的方式工作。groupBy
只是标准 SQL 中的GROUP BY
子句的等价物。换句话说,
table.groupBy($"foo", $"bar")
相当于:
SELECT foo, bar, [agg-expressions] FROM table GROUP BY foo, bar
cube
相当于CUBE
扩展GROUP BY
。它采用列列表,并将聚合表达式应用于分组列的所有可能组合。假设你有这样的数据:
val df = Seq(("foo", 1L), ("foo", 2L), ("bar", 2L), ("bar", 2L)).toDF("x", "y")
df.show
// +---+---+
// | x| y|
// +---+---+
// |foo| 1|
// |foo| 2|
// |bar| 2|
// |bar| 2|
// +---+---+
并且您使用 count 作为聚合来计算cube(x, y)
:
df.cube($"x", $"y").count.show
// +----+----+-----+
// | x| y|count|
// +----+----+-----+
// |null| 1| 1| <- count of records where y = 1
// |null| 2| 3| <- count of records where y = 2
// | foo|null| 2| <- count of records where x = foo
// | bar| 2| 2| <- count of records where x = bar AND y = 2
// | foo| 1| 1| <- count of records where x = foo AND y = 1
// | foo| 2| 1| <- count of records where x = foo AND y = 2
// |null|null| 4| <- total count of records
// | bar|null| 2| <- count of records where x = bar
// +----+----+-----+
rollup
与cube
类似的函数,它从左到右计算分层小计:
df.rollup($"x", $"y").count.show
// +----+----+-----+
// | x| y|count|
// +----+----+-----+
// | foo|null| 2| <- count where x is fixed to foo
// | bar| 2| 2| <- count where x is fixed to bar and y is fixed to 2
// | foo| 1| 1| ...
// | foo| 2| 1| ...
// |null|null| 4| <- count where no column is fixed
// | bar|null| 2| <- count where x is fixed to bar
// +----+----+-----+
只是为了比较,让我们看看普通groupBy
的结果:
df.groupBy($"x", $"y").count.show
// +---+---+-----+
// | x| y|count|
// +---+---+-----+
// |foo| 1| 1| <- this is identical to x = foo AND y = 1 in CUBE or ROLLUP
// |foo| 2| 1| <- this is identical to x = foo AND y = 2 in CUBE or ROLLUP
// |bar| 2| 2| <- this is identical to x = bar AND y = 2 in CUBE or ROLLUP
// +---+---+-----+
总结一下:
- 使用纯
GROUP BY
时,每一行在其相应的摘要中仅包含一次。 通过
GROUP BY CUBE(..)
每一行都包含在它所代表的每个级别组合的摘要中,包括通配符。从逻辑上讲,上面显示的内容等效于这样的东西(假设我们可以使用NULL
占位符):SELECT NULL, NULL, COUNT(*) FROM table UNION ALL SELECT x, NULL, COUNT(*) FROM table GROUP BY x UNION ALL SELECT NULL, y, COUNT(*) FROM table GROUP BY y UNION ALL SELECT x, y, COUNT(*) FROM table GROUP BY x, y
与
GROUP BY ROLLUP(...)
类似CUBE
,但通过从左到右填充列来分层工作。SELECT NULL, NULL, COUNT(*) FROM table UNION ALL SELECT x, NULL, COUNT(*) FROM table GROUP BY x UNION ALL SELECT x, y, COUNT(*) FROM table GROUP BY x, y
ROLLUP
和CUBE
来自数据仓库扩展,因此如果您想更好地了解其工作原理,还可以查看您喜欢的RDMBS的文档。例如,PostgreSQL在9.5中引入,这些都有相对完善的文档。
"家庭"中还有一个成员可以解释这一切 -GROUPING SETS
.我们在 PySpark/Scala 中没有它,但它存在于 SQL API 中。
GROUPING SETS
用于设计所需的任何分组组合。其他(cube
、rollup
、groupBy
)返回预定义的存在组合:
cube("id", "x", "y")
将返回()
、(id)
、(x)
、(y)
、(id, x)
、(id, y)
、(x, y)
、(id, x, y)
.
(所有可能存在的组合)。
rollup("id", "x", "y")
将只返回()
、(id)
、(id, x)
、(id, x, y)
.
(包括所提供序列开头的组合)。
groupBy("id", "x", "y")
只会返回(id, x, y)
组合。
示例
输入 df:
df = spark.createDataFrame(
[("a", "foo", 1),
("a", "foo", 2),
("a", "bar", 2),
("a", "bar", 2)],
["id", "x", "y"])
df.createOrReplaceTempView("df")
cube
df.cube("id", "x", "y").count()
和...
spark.sql(""" SELECT id, x, y, count(1) count FROM df GROUP BY GROUPING SETS ( (), (id), (x), (y), (id, x), (id, y), (x, y), (id, x, y) ) """)
+----+----+----+-----+ | id| x| y|count| +----+----+----+-----+ |null|null| 2| 3| |null|null|null| 4| | a|null| 2| 3| | a| foo|null| 2| | a| foo| 1| 1| | a|null| 1| 1| |null| foo|null| 2| | a|null|null| 4| |null|null| 1| 1| |null| foo| 2| 1| |null| foo| 1| 1| | a| foo| 2| 1| |null| bar|null| 2| |null| bar| 2| 2| | a| bar|null| 2| | a| bar| 2| 2| +----+----+----+-----+
rollup
df.rollup("id", "x", "y").count()
和...
GROUPING SETS ((), (id), (id, x), (id, x, y))
spark.sql(""" SELECT id, x, y, count(1) count FROM df GROUP BY GROUPING SETS ( (), (id), --(x), <- (not used) --(y), <- (not used) (id, x), --(id, y), <- (not used) --(x, y), <- (not used) (id, x, y) ) """)
+----+----+----+-----+ | id| x| y|count| +----+----+----+-----+ |null|null|null| 4| | a| foo|null| 2| | a| foo| 1| 1| | a|null|null| 4| | a| foo| 2| 1| | a| bar|null| 2| | a| bar| 2| 2| +----+----+----+-----+
groupBy
df.groupBy("id", "x", "y").count()
和...
GROUPING SETS ((id, x, y))
spark.sql(""" SELECT id, x, y, count(1) count FROM df GROUP BY GROUPING SETS ( --(), <- (not used) --(id), <- (not used) --(x), <- (not used) --(y), <- (not used) --(id, x), <- (not used) --(id, y), <- (not used) --(x, y), <- (not used) (id, x, y) ) """)
+---+---+---+-----+ | id| x| y|count| +---+---+---+-----+ | a|foo| 2| 1| | a|foo| 1| 1| | a|bar| 2| 2| +---+---+---+-----+
注意。以上所有返回存在的组合。在示例数据帧中,没有用于"id":"a", "x":"bar", "y":1
行。即使cube
也不会返回它。为了获得所有可能的组合(存在与否),我们应该执行以下操作(crossJoin
):
df_cartesian = spark.range(1).toDF('_tmp')
for c in (cols:=["id", "x", "y"]):
df_cartesian = df_cartesian.crossJoin(df.select(c).distinct())
df_final = (df_cartesian.drop("_tmp")
.join(df.cube(*cols).count(), cols, 'full')
)
df_final.show()
# +----+----+----+-----+
# | id| x| y|count|
# +----+----+----+-----+
# |null|null|null| 4|
# |null|null| 1| 1|
# |null|null| 2| 3|
# |null| bar|null| 2|
# |null| bar| 2| 2|
# |null| foo|null| 2|
# |null| foo| 1| 1|
# |null| foo| 2| 1|
# | a|null|null| 4|
# | a|null| 1| 1|
# | a|null| 2| 3|
# | a| bar|null| 2|
# | a| bar| 1| null|
# | a| bar| 2| 2|
# | a| foo|null| 2|
# | a| foo| 1| 1|
# | a| foo| 2| 1|
# +----+----+----+-----+
- 如果您不想要 null,请先使用以下示例将其删除 Dfwithoutnull=df.na.drop("all",seq(col name 1,col name 2)) 上面的表达式将从原始数据帧中删除空 值
2.分组由你知道我猜。
3.汇总和多维数据集是分组集运算符。 汇总是一种多维聚合和分层处理元素
在立方体中,立方体不是分层处理元素,而是在所有维度上做同样的事情。 您可以尝试grouping_id来理解抽象级别