Перейти к основному содержимому
Перейти к основному содержимому

Словарь

Словарь в ClickHouse предоставляет представление данных в памяти в формате ключ-значение из различных внутренних и внешних источников, оптимизируя запросы на поиск с очень низкой задержкой.

Словари полезны для:

  • Улучшения производительности запросов, особенно при использовании с JOINs
  • Обогащения загружаемых данных на лету без замедления процесса загрузки
Сценарии использования словаря в ClickHouse

Ускорение соединений с помощью словаря

Словари можно использовать для ускорения определенного типа JOIN: LEFT ANY типа, где ключ соединения должен совпадать с атрибутом ключа в хранилище ключ-значение.

Использование словаря с LEFT ANY JOIN

Если это так, ClickHouse может использовать словарь для выполнения Direct Join. Это самый быстрый алгоритм соединения в ClickHouse, который применим, когда подлежащий движок таблицы для правой таблицы поддерживает запросы ключ-значение с низкой задержкой. У ClickHouse есть три движка таблиц, которые предоставляют эту возможность: Join (который по сути является предрассчитанной хеш-таблицей), EmbeddedRocksDB и Dictionary. Мы опишем подход, основанный на словаре, но механика одинаковая для всех трех движков.

Алгоритм прямого соединения требует, чтобы правая таблица была поддержана словарем, так что данные, которые нужно соединить из этой таблицы, уже находятся в памяти в виде структуры данных ключ-значение с низкой задержкой.

Пример

Используя набор данных Stack Overflow, давайте ответим на вопрос: Какой пост о SQL на Hacker News является самым противоречивым?

Мы определим противоречивость как ситуацию, когда посты имеют схожее количество голосов "за" и "против". Мы вычислим эту абсолютную разницу, где значение, приближенное к 0, означает большее количество противоречий. Мы предположим, что пост должен иметь как минимум 10 голосов "за" и "против" — посты, на которые люди не голосуют, не очень противоречивы.

С нашими нормализованными данными этот запрос в настоящее время требует JOIN с использованием таблиц posts и votes:

Используйте меньшие наборы данных с правой стороны JOIN: Этот запрос может показаться более многословным, чем требуется, с фильтрацией по PostIds, происходящей как в внешнем, так и в подзапросах. Это оптимизация производительности, которая обеспечивает быстрое время отклика на запрос. Для оптимальной производительности всегда убедитесь, что правая сторона JOIN является меньшим набором и как можно более маленьким. Для советов по оптимизации производительности JOIN и понимания доступных алгоритмов рекомендуется эта серия статей в блоге.

Хотя этот запрос быстрый, он зависит от того, что мы аккуратно написали JOIN, чтобы добиться хорошей производительности. В идеале мы просто отфильтровали бы посты с содержимым "SQL", прежде чем анализировать количество UpVote и DownVote для подмножества блогов для вычисления нашей метрики.

Применение словаря

Чтобы продемонстрировать эти концепции, мы используем словарь для наших данных голосования. Поскольку словари обычно хранятся в памяти (ssd_cache является исключением), пользователи должны быть осведомлены о размере данных. Проверяем размер нашей таблицы votes:

Данные будут храниться в непакованном виде в нашем словаре, поэтому нам нужно как минимум 4 ГБ памяти, если мы хотим хранить все колонки (мы этого не сделаем) в словаре. Словарь будет реплицирован по нашему кластеру, поэтому эта величина памяти должна быть зарезервирована на узел.

В приведенном ниже примере данные для нашего словаря происходят из таблицы ClickHouse. Хотя это представляет собой самый распространенный источник словарей, поддерживается ряд источников, включая файлы, http и базы данных, включая Postgres. Как мы покажем, словари могут обновляться автоматически, что обеспечивает идеальный способ обеспечить наличие небольших наборов данных, подверженных частым изменениям, для прямых соединений.

Нашему словарю требуется первичный ключ, по которому будут выполняться запросы. Это концептуально идентично первичному ключу транзакционной базы данных и должно быть уникальным. Наш вышеуказанный запрос требует поиска по ключу соединения - PostId. Словарь должен, в свою очередь, быть заполнен общим количеством голосов "за" и "против" для каждого PostId из нашей таблицы votes. Вот запрос на получение этих данных для словаря:

Чтобы создать наш словарь, требуется следующий DDL - обратите внимание на использование нашего вышеизложенного запроса:

В self-managed OSS вышеуказанная команда должна быть выполнена на всех узлах. В ClickHouse Cloud словарь будет автоматически реплицирован на все узлы. Вышеуказанная команда была выполнена на узле ClickHouse Cloud с 64 ГБ RAM, это заняло 36 секунд для загрузки.

Чтобы подтвердить объем памяти, потребляемой нашим словарем:

Получить количество голосов "за" и "против" для конкретного PostId теперь можно с помощью простой функции dictGet. Ниже мы получаем значения для поста 11227902:

Этот запрос не только гораздо проще, но и также более чем в два раза быстрее! Это можно дополнительно оптимизировать, загрузив только посты с более чем 10 голосами "за" и "против" в словарь и храня только предварительно вычисленное противоречивое значение.

Обогащение времени запроса

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

Мы можем использовать этот словарь для обогащения результатов постов:

Аналогично нашему вышеупомянутому примеру с соединением, мы можем использовать тот же словарь, чтобы эффективно определить, откуда происходит большинство постов:

Обогащение времени индексации

В приведенном выше примере мы использовали словарь во время запроса, чтобы убрать соединение. Словари также могут использоваться для обогащения строк во время вставки. Это обычно уместно, если значение обогащения не изменяется и существует во внешнем источнике, который можно использовать для заполнения словаря. В этом случае обогащение строки во время вставки избегает поиска во время запроса в словаре.

Предположим, что Location пользователя в Stack Overflow никогда не изменяется (на самом деле это не так) - конкретно колонка Location таблицы users. Предположим, мы хотим провести аналитический запрос по таблице постов, которая содержит UserId.

Словарь предоставляет сопоставление от идентификатора пользователя к местоположению, поддерживаемое таблицей users:

Мы опускаем пользователей с Id < 0, что позволяет нам использовать тип словаря Hashed. Пользователи с Id < 0 являются системными пользователями.

Чтобы использовать этот словарь во время вставки в таблицу постов, нам нужно изменить схему:

В приведенном выше примере Location объявлен как MATERIALIZED колонка. Это означает, что значение может быть предоставлено как часть запроса INSERT и всегда будет вычисляться.

ClickHouse также поддерживает DEFAULT колонки (где значение может быть вставлено или вычислено, если не предоставлено).

Чтобы заполнить таблицу, мы можем использовать обычную команду INSERT INTO SELECT из S3:

Теперь мы можем узнать название местоположения, из которого происходит большинство постов:

Продвинутые темы словарей

Выбор LAYOUT словаря

Клауза LAYOUT управляет внутренней структурой данных для словаря. Существует несколько вариантов, и они задокументированы здесь. Некоторые советы по выбору правильного макета можно найти здесь.

Обновление словарей

Мы указали LIFETIME для словаря как MIN 600 MAX 900. LIFETIME — это интервал обновления для словаря, при этом значения здесь приводят к периодической перезагрузке в случайном интервале между 600 и 900 с. Этот случайный интервал необходим для распределения нагрузки на источник словаря при обновлении на большом количестве серверов. Во время обновлений старая версия словаря все еще может быть запрошена, при этом только начальная загрузка блокирует запросы. Обратите внимание, что установка (LIFETIME(0)) предотвращает обновление словарей. Словари могут быть принудительно перезагружены с помощью команды SYSTEM RELOAD DICTIONARY.

Для источников баз данных, таких как ClickHouse и Postgres, вы можете настроить запрос, который будет обновлять словари только в случае реальных изменений (ответ на запрос определяет это), а не через периодический интервал. Дополнительные детали можно найти здесь.

Другие типы словарей

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

Дополнительные чтения