Ответ 1
Они не предназначены для работы одинаково. groupBy
является просто эквивалентом предложения GROUP BY
в стандартном SQL. Другими словами
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|
// +---+---+
и вы вычисляете 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
// +----+----+-----+
Аналогичная функция для cube
- это rollup
, которая вычисляет иерархические промежуточные итоги слева направо:
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, так и они относительно хорошо документированы.