Читальный зал: чем меряют ответ

Комбинатор — это суффикс, а не функция

16 мин
Чему научишься
  • разбирать незнакомое имя на части: корень и суффиксы
  • пользоваться шестью суффиксами: -If, -OrNull, -Array, -Map, -ForEach, -Resample
  • собирать составные имена вроде sumMapIf и quantilesExactIf — и по суффиксам понимать, как меняется базовый агрегат
  • различать «ноль» и «нет данных»: если ни одна строка не подошла, условная сумма даёт 0, а -OrNull

Имя, которого нет в справочнике

В журнале предшественника попадается sumMapIf. Ты открываешь справочник функций зала — такого имени там нет. На соседних страницах встречаются quantilesExactIf, argMaxIf и uniqExactIf — их в списке тоже не найти.

Справочник не устарел. Эти имена и не должны лежать в нём как отдельные функции.

Агрегат в ClickHouse собирается из корня и суффиксов. Такой суффикс называется комбинатором: он меняет поведение базовой агрегатной функции, если их аргументы совместимы.

Значит, приём из прошлого урока — countIf, sumIf — был только частным случаем. -If — один из таких суффиксов.

В этом уроке разберём шесть суффиксов. Следующая ячейка показывает, как каждый из них меняет один и тот же агрегат — и, главное, как меняется форма ответа. Квадратные скобки в ней обозначают массив, то есть список значений; подробно массивы разберём в третьей главе.

Разворот журнала в пятне настольной лампы: длинное имя функции разделено тремя чертами на корень и два суффикса, под каждой частью короткая подпись; ниже столбиком шесть таких же разобранных имён, слева закрытый справочник функций, на нём сидит кот.
Имя не ищут в справочнике — его собирают из кусочков, потому справочник и закрыт.
Пять суффиксов у корня sum и шестой у count — на данных о визите. Смотри прежде всего на ФОРМУ ответа: число, NULL, массив или пара массивов.

Правило чтения незнакомого имени

Если встретил незнакомое имя , не ищи его целиком. Начни с конца: отрезай суффиксы справа налево, пока не останется знакомый корень.

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

суффиксчто делаетчто видно в ячейке
-Ifпринимает последним аргументом условие и считает только подходящие строкипо галерее 5626 всего и 2753 с планшета
-OrNullесли считать нечего, возвращает вместо 0обычный sumIf без подходящих строк дал 0, sumOrNullIf — NULL
-Arrayпринимает массив и передаёт агрегату КАЖДЫЙ его элемент13 268 по галерее: это 5626 материалов плюс 7642 действия, сложенные в одну сумму
-Mapпринимает пару массивов «ключи, значения» и складывает значения отдельно по каждому ключудва параллельных массива: три устройства и сумма по каждому
-ForEachпринимает массив и ведёт ОТДЕЛЬНЫЙ агрегат для каждой позиции[5626, 7642] — два независимых итога вместо одного
-Resampleраскладывает строки по корзинам в зависимости от ключа и считает агрегат в каждой[694, 683, 397] — три корзины без единого GROUP BY

Особенно легко перепутать -Array и -ForEach, потому что оба работают с массивами. Разница — в том, что происходит после чтения элементов.

-Array отправляет все элементы всех массивов в один агрегат. Поэтому на выходе получается одно число.

-ForEach держит отдельный агрегат для каждой позиции массива. Поэтому результат — массив той же длины: первый итог для первой позиции, второй для второй и так далее.

Ноль и отсутствие ответа — разные вещи

Отдельно стоит разобраться с -OrNull, потому что здесь меняется не способ счёта, а смысл результата.

Колонка «пустая группа: ноль» и колонка «-OrNull» отвечают на один вопрос: какова сумма по визитам, где открыто больше сотни материалов. Сами группы залов существуют, но в них нет ни одного подходящего визита.

Обычный условный агрегат возвращает 0. В отчёте это легко прочитать как измеренный факт: «материалов было ноль».

-OrNull возвращает NULL. Смысл другой: считать было нечего. Для сводки, которую читает смотритель, разница между «ноль» и «нет данных» важнее, чем кажется.

Имя снимают справа налево: sumMapIf-If-Map → корень sum. Рядом — что каждый суффикс делает с формой ответа: число, NULL, пара массивов или массив.
Комбинаторы можно сочетать: составное имя собирается из корня и нескольких суффиксов подряд. Здесь читай знакомые суффиксы: argMax возвращает значение из строки с максимальным вторым аргументом, а quantilesExact — значения на заданных уровнях распределения. Подробно эти корни разберём в следующих уроках.
Один и тот же вход, два разных исхода: -Array сливает все элементы в один агрегат и даёт 13 268, -ForEach ведёт агрегат на каждую позицию и даёт [5626, 7642].
Вопрос с собеседования

Как это спрашивают на собеседовании

Обычно дают готовое имя вроде avgMergeIf или maxMapState и просят объяснить, что оно делает. Проверяют не память и не знание длинного списка функций, а сам принцип разбора.

Нужно увидеть знакомый корень, затем снять суффиксы справа налево и объяснить, что добавляет каждый из них.

Английское имя этого механизма — combinator, «комбинатор агрегатных функций».

Суффиксы -State и -Merge относятся к тому же механизму: первый возвращает состояние вместо готового значения, второй объединяет такие состояния. О них спрашивают особенно часто, потому что на них строятся предпосчитанные витрины. В этом курсе они разбираются в главе про точность счёта.

Проверь себя
В коде встретился агрегат maxForEach(x), где x — массив из трёх чисел. Что он вернёт?
Главное из урока
вопросприёмцена
Что делает sumMapIf?разобрать имя: корень sum + -Map + -Ifсправочник открывать не пришлось
Шесть форм ответа по одной таблицешесть суффиксов у агрегатных функций1 кусок / 5272 строки — один проход на все шесть

Главное правило урока: комбинатор — это суффикс, который меняет базовую агрегатную функцию.

Поэтому запоминать набор готовых имён не нужно. Запомни сами преобразования и научись читать имя справа налево: тогда незнакомый можно разобрать на месте.

В следующем уроке подробно разберём уже мелькнувший корень argMax, а суффиксы к нему останутся теми же.