Вывод схемы JSON
ClickHouse может автоматически определить структуру JSON-данных. Это может быть использовано для непосредственного запроса JSON-данных, например, на диске с помощью clickhouse-local
или в S3-корзинах, а также/или для автоматического создания схем перед загрузкой данных в ClickHouse.
Когда использовать вывод типов
- Последовательная структура - Данные, из которых вы собираетесь вывести типы, содержат все ключи, которые вас интересуют. Вывод типов основан на выборке данных с максимальным числом строк или байтов. Данные после выборки, с дополнительными колонками, будут проигнорированы и не смогут быть запрошены.
- Последовательные типы - Типы данных для конкретных ключей должны быть совместимыми, т.е. должно быть возможно автоматически преобразовать один тип в другой.
Если у вас более динамичный JSON, к которому добавляются новые ключи и для одного и того же пути возможны несколько типов, смотрите "Работа с полуструктурированными и динамическими данными".
Обнаружение типов
Следующее предполагает, что JSON имеет последовательную структуру и имеет один тип для каждого пути.
Наши предыдущие примеры использовали простую версию набора данных Python PyPI в формате NDJSON
. В этом разделе мы изучаем более сложный набор данных с вложенными структурами - набор данных arXiv, содержащий 2,5 млн научных статей. Каждая строка в этом наборе данных, распределенная в виде NDJSON
, представляет собой опубликованную академическую статью. Пример строки представлен ниже:
Эти данные требуют гораздо более сложной схемы, чем предыдущие примеры. Мы описываем процесс определения этой схемы ниже, вводя сложные типы, такие как Tuple
и Array
.
Этот набор данных хранится в общедоступной S3-корзине по адресу s3://datasets-documentation/arxiv/arxiv.json.gz
.
Вы можете видеть, что приведенный выше набор данных содержит вложенные JSON-объекты. Хотя пользователи должны разрабатывать и версионировать свои схемы, вывод типов позволяет вывести типы из данных. Это позволяет автоматически сгенерировать DDL для схемы, избегая необходимости создавать ее вручную и ускоряя процесс разработки.
Кроме определения схемы, вывод схемы JSON автоматически определяет формат данных по расширению файла и его содержимому. Указанный выше файл автоматически определяется как NDJSON.
Используя функцию s3 с командой DESCRIBE
, мы видим, какие типы будут выведены.
Вы можете заметить, что многие из колонок определены как Nullable. Мы не рекомендуем использовать тип Nullable, когда это абсолютно не необходимо. Вы можете использовать schema_inference_make_columns_nullable, чтобы контролировать поведение, когда применяется Nullable.
Мы можем видеть, что большинство колонок автоматически определены как String
, а колонка update_date
правильно определена как Date
. Колонка versions
была создана как Array(Tuple(created String, version String))
, чтобы хранить список объектов, при этом authors_parsed
определен как Array(Array(String))
для вложенных массивов.
Автоопределение дат и временных меток можно контролировать с помощью настроек input_format_try_infer_dates
и input_format_try_infer_datetimes
соответственно (по умолчанию оба включены). Вывод объектов в виде кортежей контролируется настройкой input_format_json_try_infer_named_tuples_from_objects
. Другие настройки, которые контролируют вывод схемы для JSON, такие как автоопределение чисел, можно найти здесь.
Запрос JSON
Следующее предполагает, что JSON имеет последовательную структуру и имеет один тип для каждого пути.
Мы можем полагаться на вывод схемы для запроса JSON-данных на месте. Ниже мы находим лучших авторов за каждый год, используя тот факт, что даты и массивы автоматически определены.
Вывод схемы позволяет нам запрашивать JSON-файлы без необходимости указывать схему, ускоряя задачи анализа данных по требованию.
Создание таблиц
Мы можем полагаться на вывод схемы для создания схемы таблицы. Следующая команда CREATE AS EMPTY
вызывает вывод DDL для таблицы, и таблица создается. Это не загружает никаких данных:
Чтобы подтвердить схему таблицы, мы используем команду SHOW CREATE TABLE
:
Выше показана правильная схема для этих данных. Вывод схемы основан на выборке данных и чтении данных построчно. Значения колонок извлекаются в соответствии с форматом, при этом используются рекурсивные парсеры и эвристики для определения типа каждого значения. Максимальное число строк и байтов, читаемых из данных при выводе схемы, контролируется настройками input_format_max_rows_to_read_for_schema_inference
(по умолчанию 25000) и input_format_max_bytes_to_read_for_schema_inference
(по умолчанию 32MB). В случае неправильного определения пользователи могут предоставить подсказки, как описано здесь.
Создание таблиц из фрагментов
В приведенном выше примере используется файл на S3 для создания схемы таблицы. Пользователи могут захотеть создать схему из фрагмента одной строки. Это можно сделать с помощью функции format, как показано ниже:
Загрузка JSON-данных
Следующее предполагает, что JSON имеет последовательную структуру и имеет один тип для каждого пути.
Предыдущие команды создали таблицу, в которую можно загружать данные. Теперь вы можете вставить данные в свою таблицу, используя следующую команду INSERT INTO SELECT
:
Для примеров загрузки данных из других источников, например, из файла, смотрите здесь.
После загрузки мы можем запросить наши данные, при необходимости используя формат PrettyJSONEachRow
, чтобы показать строки в их оригинальной структуре:
Обработка ошибок
Иногда у вас могут быть неправильные данные. Например, конкретные колонки, которые не имеют правильного типа, или неправильно отформатированный JSON-объект. Для этого вы можете использовать настройки input_format_allow_errors_num
и input_format_allow_errors_ratio
, чтобы разрешить определенное количество строк, которые могут быть проигнорированы, если данные вызывают ошибки вставки. Дополнительно можно предоставить подсказки для помощи в выводе схемы.
Работа с полуструктурированными и динамическими данными
Наш предыдущий пример использовал статический JSON с известными именами и типами ключей. Это часто не так - ключи могут добавляться или их типы могут изменяться. Это распространено в случаях, таких как данные мониторинга.
ClickHouse обрабатывает это через специальный тип JSON
.
Если вы знаете, что ваш JSON очень динамичен с множеством уникальных ключей и несколькими типами для одних и тех же ключей, мы рекомендуем не использовать вывод типов с JSONEachRow
для попытки вывести колонку для каждого ключа — даже если данные находятся в формате JSON, разделенном по строкам.
Рассмотрим следующий пример из расширенной версии вышеуказанного набора данных Python PyPI. Здесь мы добавили произвольную колонку tags
с парами ключ-значение.
Образец этих данных доступен в общедоступном формате JSON, разделенном по строкам. Если мы попытаемся вывести типы для этого файла, вы обнаружите, что производительность плохая, а ответ будет крайне многословным:
Основная проблема здесь в том, что формат JSONEachRow
используется для вывода типов. Это пытается вывести тип колонки для каждого ключа в JSON — по сути, пытаясь применить статическую схему к данным без использования типа JSON
.
С тысячами уникальных колонок этот подход к выводу типов медленный. В качестве альтернативы пользователи могут использовать формат JSONAsObject
.
JSONAsObject
рассматривает весь вход как один JSON-объект и хранит его в одной колонке типа JSON
, что делает его более подходящим для высокодинамичных или вложенных JSON-данных.
Этот формат также важен в случаях, когда колонки имеют несколько типов, которые не могут быть reconciled (согласованы). Например, рассмотрим файл sample.json
со следующим JSON, разделенным по строкам:
В этом случае ClickHouse может принудительно преобразовать конфликты типов и разрешить колонку a
как Nullable(String)
.
Это принуждение типов можно контролировать с помощью ряда настроек. Приведенный выше пример зависит от настройки input_format_json_read_numbers_as_strings
.
Тем не менее, некоторые типы несовместимы. Рассмотрим следующий пример:
В этом случае любая форма преобразования типов невозможна. Команда DESCRIBE
таким образом завершится неудачно:
В этом случае JSONAsObject
рассматривает каждую строку как единый тип JSON
(который поддерживает наличие нескольких типов в одной колонке). Это имеет решающее значение:
Дальнейшее чтение
Чтобы узнать больше о выводе типов данных, вы можете обратиться к этой странице документации.