Передача uniqState между таблицами AggregatingMergeTree
Узнайте, как перенести состояние uniqState из ежедневных таблиц AggregatingMergeTree в недельные, сохраняя незавершенные агрегаты без финализации.
Как можно перенести состояние функции uniqState из таблицы AggregatingMergeTree с ежедневной периодичностью в таблицу AggregatingMergeTree с недельной периодичностью в ClickHouse? Я рассчитываю метрики с разными временными разрешениями и мне нужно сохранить состояние агрегации при переходе от дневных к недельным расчётам. Мой текущий подход заключается в создании отдельных таблиц для каждой временной granularности, но я не могу напрямую использовать uniqState из дневной таблицы в недельной агрегации. Я могу получить результаты с помощью uniqMerge, но это не подходит для хранения. Как можно извлечь и переиспользовать незавершённое состояние uniqState() между таблицами AggregatingMergeTree с разными временными granularностями?
You can transfer the uniqState function state between daily and weekly AggregatingMergeTree tables by extracting the state from the daily table and directly inserting it into the weekly table. This preserves the unfinished aggregation state rather than converting it to a final result with uniqMerge.
Contents
- Понимание хранения состояния AggregatingMergeTree
- Извлечение состояний из ежедневной таблицы
- Перенос состояний в еженедельную таблицу
- Практические шаги реализации
- Проблемы производительности
Понимание хранения состояния AggregatingMergeTree
Табличные движки AggregatingMergeTree в ClickHouse специально созданы для хранения состояний агрегирования, а не окончательных результатов. Когда вы используете uniqState(), он создаёт бинарное представление состояния агрегирования (обычно с использованием HyperLogLog или аналогичных алгоритмов для подсчёта уникальных значений), которое можно эффективно хранить и позже объединять.
Ключевой момент: AggregatingMergeTree хранит эти состояния в сжатом бинарном формате, что позволяет экономить место и автоматически объединять их при вставке новых данных с тем же первичным ключом. Согласно документации ClickHouse, такой подход значительно экономит место по сравнению с хранением отдельных точек данных.
Движок таблицы AggregatingMergeTree хранит состояния агрегирования и автоматически объединяет их по первичному ключу, что делает его идеальным для предварительной агрегации с разными временными интервалами.
Извлечение состояний из ежедневной таблицы
Чтобы извлечь состояние из вашей ежедневной таблицы без его финализации, нужно запросить колонки состояния напрямую. Хранимые состояния уже находятся в колонках типа AggregateFunction, поэтому их можно получить «как есть».
-- Извлечение состояний из ежедневной таблицы без финализации
SELECT
date,
user_id,
uniq_state_column -- Это содержит бинарное состояние, а не окончательный результат
FROM daily_table
WHERE date BETWEEN '2024-01-01' AND '2024-01-07';
Ключевой момент: колонки состояния сами по себе содержат бинарное представление, которое можно напрямую передать. Никаких преобразований не требуется – просто выберите колонку состояния в том виде, в котором она хранится в таблице.
Перенос состояний в еженедельную таблицу
После того как вы извлекли состояния из ежедневной таблицы, их можно напрямую вставить в еженедельную таблицу. Еженедельная таблица должна иметь совместимые колонки AggregateFunction, которые могут принимать тот же формат состояния.
-- Перенос состояний из ежедневной в еженедельную таблицу
INSERT INTO weekly_table
SELECT
toStartOfWeek(date) AS week_date,
user_id,
uniq_state_column -- Прямой перенос состояния
FROM daily_table
WHERE date BETWEEN '2024-01-01' AND '2024-01-07';
Этот подход работает, потому что обе таблицы используют совместимые типы AggregateFunction для той же самой агрегатной функции. Бинарный формат состояния сохраняется при переносе.
Практические шаги реализации
Ниже приведён полный пример реализации, показывающий, как настроить и перенести состояния между ежедневной и еженедельной таблицами:
-- Шаг 1: Создание ежедневной таблицы AggregatingMergeTree
CREATE TABLE daily_metrics (
date Date,
user_id String,
metrics AggregateFunction(uniq, String)
) ENGINE = AggregatingMergeTree()
ORDER BY (date, user_id);
-- Шаг 2: Создание еженедельной таблицы AggregatingMergeTree
CREATE TABLE weekly_metrics (
week_start Date,
user_id String,
metrics AggregateFunction(uniq, String)
) ENGINE = AggregatingMergeTree()
ORDER BY (week_start, user_id);
-- Шаг 3: Вставка ежедневных данных (через материализованный вид или прямую вставку)
-- Материализованный вид для ежедневных данных:
CREATE MATERIALIZED VIEW daily_mv TO daily_metrics AS
SELECT
date,
user_id,
uniqState(user_id) AS metrics
FROM raw_events
GROUP BY date, user_id;
-- Шаг 4: Перенос состояний в еженедельную таблицу
INSERT INTO weekly_metrics
SELECT
toStartOfWeek(date) AS week_start,
user_id,
metrics -- Прямой перенос состояния
FROM daily_metrics
WHERE date BETWEEN '2024-01-01' AND '2024-01-31';
Для более сложных сценариев можно использовать функцию arrayReduce, чтобы объединить состояния из нескольких ежедневных записей:
-- Объединение состояний из нескольких ежедневных записей в еженедельное состояние
INSERT INTO weekly_metrics
SELECT
toStartOfWeek(date) AS week_start,
user_id,
uniqMergeState(arraySlice(metrics, 1)) AS metrics
FROM daily_metrics
GROUP BY week_start, user_id;
Проблемы производительности
При переносе состояний между разными временными интервалами стоит учитывать следующие оптимизации:
- Пакетная обработка: Перенос состояний пакетами, а не построчно, чтобы минимизировать накладные расходы.
- Гранулярность индекса: Настройте параметр
index_granularityдля оптимальной производительности обеих таблиц. - Сжатие состояния: Бинарный формат состояния уже сжат, но стоит обратить внимание на стратегии партиционирования.
- Управление памятью: Будьте внимательны к потреблению памяти при переносе больших объёмов состояний.
Согласно исследованиям от Altinity, подход хранения состояний может значительно снизить требования к объёму хранимых данных по сравнению с хранением отдельных точек, что делает его эффективным для временных агрегаций.
Заключение
Перенос состояний функции uniqState между ежедневной и еженедельной таблицами AggregatingMergeTree достигается прямым извлечением и вставкой бинарных представлений состояний. Ключевые выводы:
- Прямой перенос состояния: Извлекайте колонки состояния из ежедневных таблиц и вставляйте их напрямую в еженедельные таблицы.
- Сохранение бинарного формата: Перевод в окончательные результаты не требуется – колонки
AggregateFunctionобрабатывают перенос состояний. - Эффективное хранение: Этот подход использует встроенное сжатие и объединение состояний ClickHouse.
- Масштабируемая архитектура: Паттерн работает для любых преобразований временных интервалов (ежедневно→еженедельно, часовой→ежедневный и т.д.).
Для оптимальной производительности рассмотрите пакетные переносы и настройку параметров таблиц в соответствии с объёмом данных и характером запросов. Такая архитектура позволяет поддерживать агрегатные состояния на разных уровнях временной granularности, минимизируя при этом расходы на хранение.