Learning Platform
Глоссарий Troubleshooting
Урок 14.04 · 25 мин
Продвинутый
topKgroupArrayuniqUpToapproximate functionsproduct analyticsheavy hitters

topK, groupArray и uniqUpTo: паттерны product analytics

Три агрегатные функции для типичных задач product analytics: topK — какие элементы встречаются чаще всего, groupArray — собрать события в массив, uniqUpTo — проверить, превышает ли число уникальных значений порог. Каждая оптимизирована для своего сценария.


Три функции: обзор

Функции для product analytics
topK -- топ-N элементовtopK(N)(column) -- approximate heavy hitters. Возвращает Array с N наиболее частыми значениями. Алгоритм Space-Saving: память O(N), не O(кардинальности). Применение: топ страниц, топ ошибок, популярные товары. Приближённый -- при очень равномерном распределении менее надёжен.
groupArray -- в массивgroupArray(N)(column) -- собирает до N значений в массив. Детерминированный: первые N значений по порядку обработки. Применение: список последних событий пользователя, сэмплирование данных, агрегация небольших групп. Без N -- собирает все значения.
uniqUpTo -- bounded countuniqUpTo(N)(column) -- возвращает точное число уникальных значений если оно <= N, иначе возвращает N+1. Память O(N). Применение: проверки 'более ли 100 уникальных клиентов в SKU', 'достиг ли сегмент 1000 пользователей'. Дешевле uniq() когда нужна только проверка порога.

topK: приближённые топ-N значения

-- Топ-10 наиболее посещаемых страниц
SELECT topK(10)(page_url) AS top_pages
FROM page_views
WHERE event_date = today();
-- Возвращает Array(String): ['/', '/products', '/checkout', ...]
-- Более полный пример: топ-10 страниц по дням
SELECT
    event_date,
    topK(10)(page_url) AS top_pages
FROM page_views
GROUP BY event_date
ORDER BY event_date DESC
LIMIT 7;

topK использует алгоритм Space-Saving: память O(N) независимо от кардинальности данных. Это принципиально отличает его от GROUP BY column ORDER BY count() LIMIT N который требует памяти пропорционально числу уникальных значений.

-- Взвешенный вариант: топ-10 страниц по суммарному времени на странице
SELECT topKWeighted(10)(page_url, time_on_page) AS top_by_engagement
FROM page_views;

topK vs GROUP BY + ORDER BY + LIMIT

ПодходТочностьПамятьКогда использовать
topK(N)ПриближённаяO(N)Аналитические дашборды, реальное время
GROUP BY ... LIMIT NТочнаяO(кардинальности)Точные отчёты, небольшие таблицы

groupArray: сбор значений в массив

-- Последние 5 событий каждого пользователя
SELECT
    user_id,
    groupArray(5)(event_type) AS last_5_events
FROM events
GROUP BY user_id;
-- Возвращает первые 5 событий по порядку обработки
WARNING

groupArray(N) собирает первые N значений по порядку обработки, который не гарантирован в ClickHouse без явного ORDER BY. Для “последних N событий по времени” используйте подзапрос с ORDER BY ts DESC перед groupArray или функцию groupArrayLast(N).

-- groupArrayLast(N): последние N значений по порядку
SELECT
    user_id,
    groupArrayLast(5)(event_type) AS last_5_events
FROM events
GROUP BY user_id;
-- Сэмплирование: случайные 100 event_id для проверки
SELECT groupArray(100)(event_id) AS sample
FROM events
WHERE event_date = today()
LIMIT 1;

groupArray без ограничения N собирает все значения в массив — будьте осторожны на больших данных: массив может вырасти до размеров таблицы.

-- Без ограничения -- все значения в один массив
SELECT groupArray(user_id) AS all_users FROM small_table;
-- Использовать только для небольших групп

uniqUpTo: проверка порогов уникальности

-- Проверка: сколько уникальных посетителей у каждого SKU?
-- Если <= 100, возвращает точное число; если > 100, возвращает 101
SELECT
    sku_id,
    uniqUpTo(100)(user_id) AS visitor_count
FROM product_views
GROUP BY sku_id;
sku_idvisitor_count
A00147
A002101
A00323

SKU A002 имеет более 100 уникальных посетителей (точное число неизвестно, возвращается N+1=101).

-- Использование в условии: найти SKU с "достаточной" аудиторией
SELECT sku_id
FROM product_views
GROUP BY sku_id
HAVING uniqUpTo(100)(user_id) >= 50;
-- Все SKU, у которых точно есть >= 50 уникальных посетителей

uniqUpTo(N) значительно дешевле uniq() или uniqExact() когда нужна только проверка порога. Память O(N) vs O(кардинальности).

Ссылка: Module 08 урок 09 содержит полное семейство uniq-функций (uniq, uniqCombined, uniqExact, uniqTheta). uniqUpTo — специализированный вариант для проверки порогов.


Сводная таблица

ФункцияТочностьПамятьВозвращаемый типТипичное применение
topK(N)ПриближённаяO(N)Array(T)Топ страниц, топ ошибок
topKWeighted(N)ПриближённаяO(N)Array(T)Топ с весовым коэффициентом
groupArray(N)ТочнаяO(N * elem_size)Array(T)Последние N событий, сэмплирование
groupArrayLast(N)ТочнаяO(N * elem_size)Array(T)Последние N по порядку
uniqUpTo(N)Точная до N, N+1 вышеO(N)UInt64Проверки пороговых значений

Ключевые выводы

  1. topK(N)(column) — приближённый топ-N через алгоритм Space-Saving. Память O(N), не зависит от кардинальности. Для точного результата — GROUP BY ... ORDER BY count() LIMIT N.
  2. groupArray(N)(column) — первые N значений в массив. groupArrayLast(N) — последние N. Без N — все значения (опасно на больших данных).
  3. uniqUpTo(N)(column) — точное число уникальных если <= N, иначе N+1. Дешевле uniq() когда нужна только проверка порога.
  4. Паттерн uniqUpTo в HAVING: HAVING uniqUpTo(100)(col) < 101 — это фильтр “меньше 100 уникальных значений”.
  5. Все три функции оптимизированы по памяти: O(N) vs O(кардинальности) для наивных аналогов.
Агрегация в PostgreSQL: HashAggregate, GroupAggregate и memory spill Приближённые алгоритмы: HyperLogLog, Count-Min Sketch и Space-Saving

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 3. topK(10)(page_url) вернул массив из 8 элементов, а не из 10. Что это означает?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 8