Агрегатные функции в Hive

Агрегатные функции Hive — это встроенные функции, которые принимают несколько значений и возвращают одно агрегированное значение. В данной статье приведены примеры и рекомендации по использованию базовых и расширенных агрегатных функций Hive. Полный список агрегатных функций, поддерживаемых в Hive по умолчанию, доступен в документации Apache Hive.

Тестовая база данных

В данной статье для демонстрации агрегатных функций используются Hive-таблицы employees и transactions, структура которых описана ниже.

SELECT * FROM employees;
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+
| employees.id  | employees.name  | employees.last_name  |      employees.email       | employees.age  | employees.salary  | employees.dept_id  |
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+
| 1             | Ivan            | Ivanov               | ivan_ivanov123@mail.ru     | 30             | 1000              | 1                  |
| 2             | Sarah           | Connor               | sarah_connor123@yahoo.com  | 35             | 1500              | 2                  |
| 3             | Rick            | Sanchez              | rick_123@mail.ru           | 29             | 1300              | 2                  |
| 4             | John            | Smith                | john_smith123@gmail.com    | 29             | 2000              | 3                  |
+---------------+-----------------+----------------------+----------------------------+----------------+-------------------+--------------------+


SELECT * FROM transactions;
+----------------------+----------------------+--------------------------+------------------------+
| transactions.txn_id  | transactions.acc_id  | transactions.txn_amount  | transactions.txn_date  |
+----------------------+----------------------+--------------------------+------------------------+
| 1                    | 101                  | 10.20                    | 2023-10-26             |
| 2                    | 101                  | 102.30                   | 2023-10-26             |
| 3                    | 102                  | 95.00                    | 2023-10-26             |
| 4                    | 103                  | 900.50                   | 2023-10-27             |
| 5                    | 102                  | 910.50                   | 2023-10-27             |
| 6                    | 101                  | 850.00                   | 2023-10-27             |
+----------------------+----------------------+--------------------------+------------------------+
SQL для создания тестовых таблиц

 
Для создания и наполнения тестовых таблиц Hive выполните следующий SQL с помощью /bin/beeline.

CREATE TABLE IF NOT EXISTS employees (id int, name string, last_name string, email string, age int, salary int, dept_id int)
COMMENT 'Employee Table'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

INSERT INTO employees VALUES
(1, 'Ivan', 'Ivanov', 'ivan_ivanov123@mail.ru', 30, 1000, 1),
(2, 'Sarah', 'Connor', 'sarah_connor123@yahoo.com', 35, 1500, 2),
(3, 'Rick', 'Sanchez', 'rick_123@mail.ru', 29, 1300, 2),
(4, 'John', 'Smith', 'john_smith123@gmail.com', 29, 2000, 3);


CREATE TABLE IF NOT EXISTS transactions(txn_id int, acc_id int, txn_amount decimal(10,2), txn_date date)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe';

INSERT INTO transactions VALUES
(1, 101, 10.20, '2023-10-26'),
(2, 101, 102.30, '2023-10-26'),
(3, 102, 95.00, '2023-10-26'),
(4, 103, 900.50, '2023-10-27'),
(5, 102, 910.50, '2023-10-27'),
(6, 101, 850.00, '2023-10-27');

Базовая агрегация

Функция COUNT(col) возвращает общее количество строк в результирующем наборе данных.

SELECT COUNT(id) AS emp_total_cnt FROM employees;

Результат:

+----------------+
| emp_total_cnt  |
+----------------+
| 4              |
+----------------+
РЕКОМЕНДАЦИЯ
С помощью ключевого слова DISTINCT можно получить агрегированное значение только для уникальных значений в столбце.

Функции MIN() и MAX() возвращают минимальное/максимальное значение числового столбца.

SELECT MIN(salary) from employees;

Результат:

+-------+
|  _c0  |
+-------+
| 1000  |
+-------+

Функция AVG() возвращает среднее значение числового столбца. Функция не может использоваться внутри предложения WHERE. Например, следующий запрос приведет к ошибке:

SELECT e.salary, e.age
FROM employees e
WHERE e.age > AVG(e.age);

Текст ошибки:

Error: Error while compiling statement: FAILED: SemanticException [Error 10128]: Line 3:14 Not yet supported place for UDAF 'avg' (state=42000,code=10128)

В этом конкретном случае в качестве обходного пути можно вложить AVG() внутрь подзапроса как показано ниже.

SELECT e.age, e.last_name
FROM employees e
WHERE e.age > (SELECT AVG(age) FROM employees);

Результат успешного выполнения запроса:

+--------+--------------+
| e.age  | e.last_name  |
+--------+--------------+
| 35     | Connor       |
+--------+--------------+

Другие агрегатные функции Hive

Помимо стандартных агрегатных функций SQL, таких как SUM, AVG и прочих, Hive предоставляет дополнительные функции, которые могут пригодиться при анализе наборов данных. Например, с помощью collect_*(col) можно упаковать все значения столбца col в список или множество.

SELECT collect_set(age) FROM employees; (1)
SELECT d.dep_name AS department_name, collect_list(e.age) AS ages (2)
FROM employees e
    JOIN departments d
    ON e.dept_id=d.id
GROUP BY d.dep_name;
1 Возвращает единственную строку с множеством уникальных значений.
2 Возвращает список значений для каждого департамента.

 

Результат:

+-------------+
|     _c0     |
+-------------+
| [30,35,29]  |
+-------------+

+------------------+----------+
| department_name  |   ages   |
+------------------+----------+
| it               | [35,29]  |
| sales            | [30]     |
| support          | [29]     |
+------------------+----------+

Hive также предоставляет специальные функции для вычисления математических показателей, таких как отклонение, дисперсия и другие. Примеры использования некоторых из них показаны ниже.

SELECT variance(salary) FROM employees; (1)
SELECT var_pop(salary) FROM employees; (1)
SELECT var_samp(salary) FROM employees; (2)
SELECT stddev_pop(salary) FROM employees; (3)
SELECT stddev_samp(salary) FROM employees; (4)
1 Запросы возвращают показатель дисперсии для числового столбца salary.
2 Возвращает показатель несмещенной выборочной дисперсии (unbiased sample variance) для столбца.
3 Возвращает статистическое стандартное отклонение для значений в столбце.
4 Возвращает показатель несмещенного выборочного стандартного отклонения (unbiased sample standard deviation) для числового столбца.

 
Результат:

SELECT variance(salary) FROM employees;
+-----------+
|    _c0    |
+-----------+
| 132500.0  |
+-----------+

SELECT var_pop(salary) FROM employees;
+-----------+
|    _c0    |
+-----------+
| 132500.0  |
+-----------+

SELECT var_samp(salary) FROM employees;
+---------------------+
|         _c0         |
+---------------------+
| 176666.66666666666  |
+---------------------+

SELECT stddev_pop(salary) FROM employees;
+--------------------+
|        _c0         |
+--------------------+
| 364.0054944640259  |
+--------------------+

SELECT stddev_samp(salary) FROM employees;
+---------------------+
|         _c0         |
+---------------------+
| 420.31734043061635  |
+---------------------+

Полный список поддерживаемых агрегатных функций доступен в документации Apache Hive.

Расширенная агрегация

GROUPING SETS

Предложение GROUPING SETS, используемое в паре с GROUP BY, позволяет указывать несколько критериев GROUP BY в одном запросе. Использование нескольких группирующих наборов (например, GROUPING SETS (a,b)) эквивалентно выполнению нескольких запросов с разными выражениями GROUP BY a, GROUP BY b и объединенных с помощью UNION. Стоит отметить, что выборка с помощью группирующих наборов выполняется за одно сканирование таблицы, а не в несколько итераций, как в случае с отдельными запросами, объединенными UNION.

В следующем примере используется только один группирующий набор (GROUPING SETS (acc_id)), который группирует результаты по аккаунту, но без агрегации по дате.

SELECT acc_id, txn_date, SUM(txn_amount) as total_paid
FROM transactions
GROUP BY acc_id, txn_date
GROUPING SETS (acc_id);

Результатом такого запроса является общая сумма, оплаченная каждым аккаунтом. Значения NULL в столбце txn_date указывают на отсутствие агрегации по дате.

+---------+-----------+-------------+
| acc_id  | txn_date  | total_paid  |
+---------+-----------+-------------+
| 101     | NULL      | 962.50      |
| 102     | NULL      | 1005.50     |
| 103     | NULL      | 900.50      |
+---------+-----------+-------------+

В следующем примере показано использование нескольких группирующих наборов (GROUPING SETS (acc_id, txn_date)).

SELECT acc_id, txn_date, SUM(txn_amount) as total_paid, grouping__id
FROM transactions
GROUP BY acc_id, txn_date
GROUPING SETS (acc_id, txn_date);

В этом случае результат выборки содержит наборы строк, сгруппированных по txn_date и acc_id:

+---------+-------------+-------------+
| acc_id  |  txn_date   | total_paid  |
+---------+-------------+-------------+
| NULL    | 2023-10-26  | 207.50      |
| NULL    | 2023-10-27  | 2661.00     |
| 101     | NULL        | 962.50      |
| 102     | NULL        | 1005.50     |
| 103     | NULL        | 900.50      |
+---------+-------------+-------------+

Значения NULL указывают, что агрегация по данному столбцу не выполнялась. Обратите внимание, что полученный результат представляет собой UNION двух результатов, полученных с помощью следующих запросов:

SELECT NULL, txn_date, SUM(txn_amount)
FROM transactions
GROUP BY txn_date
UNION
SELECT acc_id, NULL, SUM(txn_amount)
FROM transactions
GROUP BY acc_id;
ВАЖНО

Выполнение отдельных запросов с UNION запускает две задачи вместо одной и потенциально может занять больше времени.

WITH CUBE

Функция CUBE используется вместе с GROUP BY для вычисления всех возможных комбинаций агрегации столбцов, указанных в GROUP BY. Следующие выражения HiveQL тождественны:

... GROUP BY a, b, c WITH CUBE
-- эквивалентно:
... GROUP BY a, b, c GROUPING SETS (
    (a, b, c), (a, b), (b, c), (a, c), (a), (b), (c), ( )
)

Ниже показан пример использования WITH CUBE.

SELECT acc_id, txn_date, SUM(txn_amount) as total_sum
FROM transactions
GROUP BY acc_id, txn_date WITH CUBE;

Результат содержит комбинацию всех возможных способов группировки данных:

+---------+-------------+-------------+
| acc_id  |  txn_date   | total_sum   |
+---------+-------------+-------------+
| NULL    | NULL        | 2868.50     |
| NULL    | 2023-10-26  | 207.50      |
| NULL    | 2023-10-27  | 2661.00     |
| 101     | NULL        | 962.50      |
| 101     | 2023-10-26  | 112.50      |
| 101     | 2023-10-27  | 850.00      |
| 102     | NULL        | 1005.50     |
| 102     | 2023-10-26  | 95.00       |
| 102     | 2023-10-27  | 910.50      |
| 103     | NULL        | 900.50      |
| 103     | 2023-10-27  | 900.50      |
+---------+-------------+-------------+

В этом примере использование конструкции WITH CUBE эквивалентно следующему запросу:

SELECT acc_id, txn_date, SUM(txn_amount) as total_sum
FROM transactions
GROUP BY acc_id, txn_date
GROUPING SETS ((acc_id, txn_date), acc_id, txn_date, ( ));

WITH ROLLUP

Функция ROLLUP используется вместе с GROUP BY для вычисления нескольких уровней промежуточных результатов по заданной группе измерений. Функция вычисляет промежуточные результаты агрегации от самого детального уровня до самого общего, следуя списку критериев, указанных в GROUP BY. Следующие конструкции HiveQL тождественны:

... GROUP BY a, b, c, WITH ROLLUP
-- эквивалентно:
... GROUP BY a, b, c GROUPING SETS ( (a, b, c), (a, b), (a), ( ))

Ниже показан пример использования WITH ROLLUP.

SELECT acc_id, txn_date, SUM(txn_amount) as total_sum
FROM transactions
GROUP BY acc_id, txn_date WITH ROLLUP;

Результат содержит записи с различными уровнями агрегации — от наиболее детальной (сумма, оплаченная определенным аккаунтом в конкретный день) до наиболее общих показателей (общая сумма уплаченных денег).

+---------+-------------+------------+
| acc_id  |  txn_date   | total_sum  |
+---------+-------------+------------+
| NULL    | NULL        | 2868.50    |
| 101     | NULL        | 962.50     |
| 101     | 2023-10-26  | 112.50     |
| 101     | 2023-10-27  | 850.00     |
| 102     | NULL        | 1005.50    |
| 102     | 2023-10-26  | 95.00      |
| 102     | 2023-10-27  | 910.50     |
| 103     | NULL        | 900.50     |
| 103     | 2023-10-27  | 900.50     |
+---------+-------------+------------+

В этом примере использование конструкции ROLLUP эквивалентно следующему запросу:

SELECT acc_id, txn_date, SUM(txn_amount) as total_sum
FROM transactions
GROUP BY acc_id, txn_date
GROUPING SETS ((acc_id, txn_date), acc_id, ( ));
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней