Работа с JSON в ClickHouse
В этом руководстве рассматриваются типовые подходы к работе с JSON‑данными, реплицируемыми из MongoDB в ClickHouse через ClickPipes.
Предположим, что мы создали коллекцию t1 в MongoDB для отслеживания клиентских заказов:
Коннектор MongoDB CDC реплицирует документы MongoDB в ClickHouse, используя нативный тип данных JSON. Реплицированная таблица t1 в ClickHouse будет содержать следующую строку:
Схема таблицы
Реплицируемые таблицы используют эту стандартную схему:
_id: Первичный ключ из MongoDBdoc: Документ MongoDB, реплицируемый в тип данных JSON_peerdb_synced_at: Фиксирует время последней синхронизации строки_peerdb_version: Отслеживает версию строки; увеличивается при обновлении или удалении строки_peerdb_is_deleted: Показывает, удалена ли строка
Движок таблицы ReplacingMergeTree
ClickPipes сопоставляет коллекции MongoDB с ClickHouse, используя семейство движков таблиц ReplacingMergeTree. В этом движке обновления моделируются как вставки с более новой версией (_peerdb_version) документа для заданного первичного ключа (_id), что обеспечивает эффективную обработку обновлений, замен и удалений как версионных вставок.
ReplacingMergeTree асинхронно очищает дубликаты в фоновом режиме. Чтобы гарантировать отсутствие дубликатов для одной и той же строки, используйте модификатор FINAL. Например:
Обработка удалений
Удаления из MongoDB реплицируются как новые строки, помеченные как удалённые с помощью столбца _peerdb_is_deleted. Обычно такие строки следует отфильтровывать в запросах:
Вы также можете создать политику на уровне строк, чтобы автоматически отфильтровывать удалённые строки вместо того, чтобы указывать фильтр в каждом запросе:
Выполнение запросов к данным JSON
Вы можете напрямую обращаться к полям JSON, используя точечную нотацию:
При выполнении запросов к вложенным полям объекта с использованием точечной нотации не забудьте добавить оператор ^:
Динамический тип
В ClickHouse каждое поле JSON имеет тип Dynamic. Динамический тип позволяет ClickHouse хранить значения любого типа, не зная этот тип заранее. Это можно проверить с помощью функции toTypeName:
Чтобы изучить исходный тип (или типы) данных для поля, вы можете воспользоваться функцией dynamicType. Обратите внимание, что для одного и того же имени поля в разных строках могут быть разные типы данных:
Обычные функции работают с типом Dynamic так же, как и с обычными столбцами:
Пример 1: Разбор дат
Пример 2: Условная логика
Пример 3: Операции с массивами
Приведение типов полей
Агрегатные функции в ClickHouse не работают напрямую с типом dynamic. Например, если вы попытаетесь напрямую использовать функцию sum для типа dynamic, вы получите следующую ошибку:
Чтобы использовать агрегатные функции, приведите поле к соответствующему типу с помощью функции CAST или синтаксиса :::
Приведение значения из динамического типа к его базовому типу данных (определяется dynamicType) обладает высокой производительностью, так как ClickHouse уже хранит значение во внутреннем представлении этого базового типа.
Уплощение JSON
Обычное представление
Вы можете создавать обычные представления поверх JSON-таблицы, чтобы инкапсулировать логику уплощения/приведения типов/преобразования и запрашивать данные в виде, похожем на реляционную таблицу. Обычные представления являются лёгкими, так как они хранят только сам запрос, а не исходные данные. Например:
У этого представления будет следующая схема:
Теперь вы можете выполнять запросы к этому представлению так же, как к денормализованной («расплющенной») таблице:
Обновляемое материализованное представление
Вы можете создать обновляемые материализованные представления, которые позволяют планировать выполнение запроса для дедупликации строк и сохранения результатов в денормализованной целевой таблице. При каждом запланированном обновлении целевая таблица заменяется последними результатами запроса.
Ключевое преимущество этого подхода заключается в том, что запрос с использованием ключевого слова FINAL выполняется только один раз во время обновления, устраняя необходимость выполнения последующих запросов к целевой таблице с использованием FINAL.
Недостаток заключается в том, что данные в целевой таблице актуальны только на момент последнего обновления. Для многих сценариев интервалы обновления от нескольких минут до нескольких часов обеспечивают хороший баланс между актуальностью данных и производительностью запросов.
Теперь вы можете напрямую выполнять запросы к таблице flattened_t1, не используя модификатор FINAL:
Инкрементальное материализованное представление
Если вам нужно получать доступ к плоским (flattened) столбцам в режиме реального времени, вы можете создать инкрементальное материализованное представление. Если в вашей таблице часто происходят обновления, не рекомендуется использовать модификатор FINAL в материализованном представлении, так как каждое обновление будет запускать операцию слияния. Вместо этого вы можете выполнять дедупликацию данных на этапе выполнения запроса, построив обычное представление поверх материализованного представления.
Теперь вы можете выполнить запрос к представлению flattened_t1_final следующим образом: