В этом руководстве вы узнаете, как использовать массивы в ClickHouse, а также некоторые из наиболее часто используемых функций для работы с массивами.
Введение в массивы
array:
[]:
Создание массивов разных типов
Создание массивов разных типов
Вы можете использовать настройку Затем вы также можете извлекать типы из массива по имени типа:
use_variant_as_common_type, чтобы изменить описанное выше поведение по умолчанию.
Это позволяет использовать тип Variant в качестве результирующего типа для функций if/multiIf/array/map, когда для типов аргументов нет общего типа.Например:[] — удобный способ доступа к элементам массива.
В ClickHouse важно помнить, что индекс массива всегда начинается с 1.
Это может отличаться от других языков программирования, к которым вы привыкли, где индексация массивов начинается с нуля.
Например, имея массив, вы можете выбрать его первый элемент, написав:
Функции для работы с массивами
функции length, arrayEnumerate, indexOf и has*
length возвращает количество элементов в массиве:
arrayEnumerate, чтобы получить массив индексов элементов:
indexOf:
indexOfAssumeSorted.
Функции has, hasAll и hasAny полезны, чтобы определить, содержит ли массив заданное значение.
Рассмотрим следующий пример:
Анализ данных о рейсах с помощью функций для работы с массивами
groupArray
groupArray, которая берет значения указанного столбца из каждой строки и объединяет их в массив.
Выполните запрос ниже, чтобы посмотреть, как это работает:
toStringCutToZero в приведенном выше запросе используется для удаления нулевых символов, которые встречаются после трехбуквенного кода некоторых аэропортов.
Когда данные представлены в таком формате, мы можем легко определить порядок самых загруженных аэропортов, вычислив длину собранных массивов “Destinations”:
arrayMap и arrayZip
arrayMap — один из примеров такой функции высшего порядка; она возвращает новый массив на основе переданного массива, применяя лямбда-функцию к каждому элементу исходного массива.
Выполните приведённый ниже запрос, который использует функцию arrayMap, чтобы увидеть, какие рейсы были задержаны, а какие вылетели вовремя.
Для пар пунктов отправления/назначения он показывает бортовой номер и статус каждого рейса:
В приведённом выше запросе функция arrayMap принимает одноэлементный массив [DepDelayMinutes] и применяет к нему лямбда-функцию d -> if(d >= 30, 'DELAYED', if(d >= 15, 'WARNING', 'ON-TIME', чтобы отнести значение к определённой категории.
Затем первый элемент результирующего массива извлекается с помощью [DepDelayMinutes][1].
Функция arrayZip объединяет массив Tail_Number и массив statuses в один массив.
arrayFilter
DEN, ATL и DFW:
В запросе выше мы передаём лямбда-функцию в качестве первого аргумента функции arrayFilter.
Эта лямбда-функция принимает значение задержки в минутах (d) и возвращает 1, если условие выполняется, и 0 — в противном случае.
arraySort и arrayIntersect
arraySort и arrayIntersect.
arraySort принимает массив и по умолчанию сортирует его элементы по возрастанию, хотя в неё также можно передать лямбда-функцию, чтобы задать порядок сортировки.
arrayIntersect принимает несколько массивов и возвращает массив с элементами, которые присутствуют во всех этих массивах.
Выполните запрос ниже, чтобы увидеть эти две функции для работы с массивами в действии:
Запрос работает в два основных этапа.
Сначала он создаёт временный набор данных airport_routes с помощью Common Table Expression (CTE): в нём рассматриваются все рейсы за 1 января 2024 года, и для каждого аэропорта вылета строится отсортированный список всех уникальных пунктов назначения, которые он обслуживает.
Например, в результирующем наборе airport_routes для DEN может быть массив со всеми городами, в которые из него выполняются рейсы, например ['ATL', 'BOS', 'LAX', 'MIA', ...], и так далее.
На втором этапе запрос берёт пять крупных узловых аэропортов США (DEN, ATL, DFW, ORD и LAS) и сравнивает все возможные пары.
Для этого используется перекрёстное соединение, которое создаёт все комбинации этих аэропортов.
Затем для каждой пары применяется функция arrayIntersect, чтобы найти пункты назначения, присутствующие в списках обоих аэропортов.
Функция length подсчитывает, сколько у них общих пунктов назначения.
Условие a1.Origin < a2.Origin гарантирует, что каждая пара появляется только один раз.
Без него в результатах были бы и JFK-LAX, и LAX-JFK как отдельные строки, хотя это одно и то же сравнение.
Наконец, запрос сортирует результаты так, чтобы показать пары аэропортов с наибольшим числом общих пунктов назначения, и возвращает только первые 10.
Это позволяет увидеть, у каких крупных хабов маршрутные сети пересекаются сильнее всего. Это может указывать на конкурентные рынки, где несколько авиакомпаний обслуживают одни и те же пары городов, или на хабы, обслуживающие схожие географические регионы и потенциально подходящие в качестве альтернативных пересадочных узлов для пассажиров.
arrayReduce
arrayReduce, чтобы найти среднюю и максимальную задержку
для каждого маршрута из международного аэропорта Денвера:
В примере выше мы использовали arrayReduce, чтобы найти среднюю и максимальную задержки для различных рейсов с вылетом из DEN.
arrayReduce применяет агрегатную функцию, указанную в первом параметре функции, к элементам переданного массива, указанного во втором параметре.
arrayJoin
arrayJoin.
arrayJoin «разворачивает» массив, создавая отдельную строку для каждого его элемента.
Это похоже на SQL-функции UNNEST или EXPLODE в других базах данных.
В отличие от большинства функций для работы с массивами, которые возвращают массивы или скалярные значения, arrayJoin кардинально меняет результирующий набор, увеличивая число строк.
Рассмотрим запрос ниже, который возвращает массив значений от 0 до 100 с шагом 10.
Этот массив можно интерпретировать как разные значения задержки: 0 минут, 10 минут, 20 минут и так далее.
С помощью arrayJoin можно написать запрос, который покажет, сколько было задержек вплоть до указанного числа минут между двумя аэропортами.
Запрос ниже строит гистограмму распределения задержек рейсов из Denver (DEN) в Miami (MIA) за 1 января 2024 года с использованием накопительных бакетов задержки:
В запросе выше мы возвращаем массив задержек с помощью выражения CTE (выражения WITH).
Destination преобразует код пункта назначения в строку.
Мы используем arrayJoin, чтобы развернуть массив задержек в отдельные строки.
Каждое значение из массива delay становится отдельной строкой с псевдонимом del,
и в результате мы получаем 10 строк: одну для del=0, одну для del=10, одну для del=20 и т. д.
Для каждого порога задержки (del) запрос подсчитывает, сколько рейсов имели задержку, большую или равную этому порогу,
с помощью countIf(DepDelayMinutes >= del).
У arrayJoin также есть SQL-эквивалент — ARRAY JOIN.
Ниже для сравнения приведён тот же запрос, но с использованием этого SQL-эквивалента:
Следующие шаги
groupArray, arrayFilter, arrayMap, arrayReduce и arrayJoin.
Чтобы продолжить изучение темы, обратитесь к полному справочнику по функциям для работы с массивами и познакомьтесь с дополнительными функциями, такими как arrayFlatten, arrayReverse и arrayDistinct.
Также вам может быть полезно узнать о связанных структурах данных, таких как Tuple, типы JSON и Map, которые хорошо сочетаются с массивами.
Потренируйтесь применять эти концепции к собственным наборам данных и поэкспериментируйте с различными запросами в Песочнице ClickHouse или на других демонстрационных наборах данных.
Массивы — одна из ключевых возможностей ClickHouse, позволяющая выполнять эффективные аналитические запросы. Чем увереннее вы будете работать с функциями для массивов, тем сильнее они будут упрощать сложные агрегации и анализ временных рядов.
Если хотите узнать о массивах еще больше, рекомендуем посмотреть видео ниже на YouTube от Mark, нашего штатного эксперта по данным: