Тип данных JSON
Тип JSON
хранит документы формата JavaScript Object Notation (JSON) в одной колонке.
Если вы хотите использовать тип JSON
и для примеров на этой странице, пожалуйста, используйте:
:::
Для объявления колонки типа JSON
вы можете использовать следующий синтаксис:
Где параметры в синтаксисе выше определяются следующим образом:
Параметр | Описание | Значение по умолчанию |
---|---|---|
max_dynamic_paths | Необязательный параметр, указывающий, сколько путей может храниться отдельно в виде под-колонок в одном блоке данных, который хранится отдельно (например, в одной части данных для таблицы MergeTree). Если этот лимит превышен, все остальные пути будут храниться вместе в одной структуре. | 1024 |
max_dynamic_types | Необязательный параметр от 1 до 255 , указывающий, сколько различных типов данных может храниться внутри одной колонки пути с типом Dynamic в одном блоке данных, который хранится отдельно (например, в одной части данных для таблицы MergeTree). Если этот лимит превышен, все новые типы будут преобразованы в тип String . | 32 |
some.path TypeName | Необязательная подсказка типа для конкретного пути в JSON. Такие пути всегда будут храниться как под-колонки с указанным типом. | |
SKIP path.to.skip | Необязательная подсказка для конкретного пути, который следует пропустить во время парсинга JSON. Такие пути никогда не будут храниться в колонке JSON. Если указанный путь является вложенным JSON объектом, вся вложенная структура будет пропущена. | |
SKIP REGEXP 'path_regexp' | Необязательная подсказка с регулярным выражением, которое используется для пропуска путей во время парсинга JSON. Все пути, соответствующие этому регулярному выражению, никогда не будут храниться в колонке JSON. |
Создание JSON
В этом разделе мы рассмотрим различные способы создания JSON
.
Использование JSON
в определении колонки таблицы
Использование CAST с ::JSON
Можно преобразовать различные типы, используя специальный синтаксис ::JSON
.
CAST из String
в JSON
CAST из Tuple
в JSON
CAST из Map
в JSON
CAST из устаревшего Object('json')
в JSON
Пути JSON хранятся в развернутом виде. Это означает, что когда объект JSON формируется из пути, такого как a.b.c
, невозможно узнать, должен ли объект быть сконструирован как { "a.b.c" : ... }
или { "a" : {"b" : {"c" : ... }}}
. Наша реализация всегда предполагает последнее.
Например:
вернет:
и не:
Чтение путей JSON как под-колонок
Тип JSON
поддерживает чтение каждого пути как отдельной под-колонки.
Если тип запрашиваемого пути не указан в объявлении типа JSON,
то под-колонка пути всегда будет иметь тип Dynamic.
Например:
Если запрашиваемый путь не был найден в данных, он будет заполнен значениями NULL
:
Давайте проверим типы данных возвращаемых под-колонок:
Как мы видим, для a.b
тип — UInt32
, как мы указали это в объявлении типа JSON,
а для всех остальных под-колонок тип — Dynamic
.
Также возможно читать под-колонки типа Dynamic
, используя специальный синтаксис json.some.path.:TypeName
:
Под-колонки типа Dynamic
могут быть преобразованы в любой тип данных. В этом случае будет выброшено исключение, если внутренний тип внутри Dynamic
не может быть приведен к запрашиваемому типу:
Чтение вложенных объектов JSON как под-колонок
Тип JSON
поддерживает чтение вложенных объектов как под-колонок с типом JSON
, используя специальный синтаксис json.^some.path
:
Чтение под-объектов как под-колонок может быть неэффективным, так как это может потребовать почти полного сканирования данных JSON.
Вывод типов для путей
Во время парсинга JSON
ClickHouse пытается обнаружить наиболее подходящий тип данных для каждого пути JSON.
Это работает аналогично автоматическому выводу схемы из входных данных,
и контролируется теми же настройками:
- input_format_try_infer_integers
- input_format_try_infer_dates
- input_format_try_infer_datetimes
- schema_inference_make_columns_nullable
- input_format_json_try_infer_numbers_from_strings
- input_format_json_infer_incomplete_types_as_strings
- input_format_json_read_numbers_as_strings
- input_format_json_read_bools_as_strings
- input_format_json_read_bools_as_numbers
- input_format_json_read_arrays_as_strings
Давайте рассмотрим несколько примеров:
Обработка массивов объектов JSON
Пути JSON, содержащие массив объектов, разбираются как тип Array(JSON)
и вставляются в колонку типа Dynamic
для этого пути.
Чтобы прочитать массив объектов, вы можете извлечь его из колонки Dynamic
как под-колонку:
Как вы могли заметить, параметры max_dynamic_types
/max_dynamic_paths
вложенного типа JSON
сократили свои значения по сравнению с значениям по умолчанию.
Это необходимо, чтобы избежать чрезмерного роста количества под-колонок для вложенных массивов объектов JSON.
Давайте попробуем прочитать под-колонки из колонки JSON
:
Мы можем избежать написания имен под-колонок Array(JSON)
, используя специальный синтаксис:
Количество []
после пути указывает уровень массива. Например, json.path[][]
будет преобразовано в json.path.:Array(Array(JSON))
Давайте проверим пути и типы внутри нашего Array(JSON)
:
Давайте прочитаем под-колонки из колонки Array(JSON)
:
Мы также можем читать под-объектные под-колонки из вложенного JSON
:
Чтение типа JSON из данных
Все текстовые форматы
(JSONEachRow
,
TSV
,
CSV
,
CustomSeparated
,
Values
, и т.д.) поддерживают чтение типа JSON
.
Примеры:
Для текстовых форматов, таких как CSV
/TSV
/и т.д., JSON
разбирается из строки, содержащей JSON объект:
Достижение предела динамических путей внутри JSON
Тип данных JSON
может хранить только ограниченное количество путей в виде отдельных под-колонок внутри.
По умолчанию этот лимит — 1024
, но вы можете изменить его в объявлении типа, используя параметр max_dynamic_paths
.
Когда лимит достигнут, все новые пути, вставляемые в колонку JSON
, будут храниться в одной общей структуре данных.
Все еще возможно читать такие пути как под-колонки,
но это потребует чтения всей общей структуры данных, чтобы извлечь значения этого пути.
Этот лимит нужен, чтобы избежать наличия огромного количества различных под-колонок, что может сделать таблицу непригодной для использования.
Давайте посмотрим, что происходит, когда лимит достигается в нескольких различных сценариях.
Достижение предела во время парсинга данных
Во время парсинга объектов JSON
из данных, когда лимит достигнут для текущего блока данных,
все новые пути будут храниться в общей структуре данных. Мы можем использовать следующие две функции для интроспекции: JSONDynamicPaths
, JSONSharedDataPaths
:
Как мы видим, после вставки путей e
и f.g
предел был достигнут,
и они были вставлены в общую структуру данных.
Во время слияний частей данных в движках таблиц MergeTree
Во время слияния нескольких частей данных в таблице MergeTree
колонка JSON
в результирующей части данных может достичь предела динамических путей и не сможет сохранить все пути из исходных частей в виде подколонок. В этом случае ClickHouse выбирает, какие пути останутся в виде подколонок после слияния, а какие пути будут сохранены в общей структуре данных. В большинстве случаев ClickHouse старается сохранить пути, которые содержат наибольшее количество ненулевых значений, а перенести наиболее редкие пути в общую структуру данных. Однако это зависит от реализации.
Давайте посмотрим на пример такого слияния. Сначала создадим таблицу с колонкой JSON
, установим предел динамических путей на 3
, а затем вставим значения с 5
различными путями:
Каждая вставка создаст отдельную часть данных, где колонка JSON
будет содержать единственный путь:
Теперь давайте объединим все части в одну и посмотрим, что произойдет:
Как мы видим, ClickHouse сохранил наиболее частые пути a
, b
и c
, перенес пути d
и e
в общую структуру данных.
Функции интроспекции
Существует несколько функций, которые могут помочь исследовать содержимое колонки JSON:
JSONAllPaths
JSONAllPathsWithTypes
JSONDynamicPaths
JSONDynamicPathsWithTypes
JSONSharedDataPaths
JSONSharedDataPathsWithTypes
distinctDynamicTypes
distinctJSONPaths and distinctJSONPathsAndTypes
Примеры
Давайте исследуем содержимое набора данных GH Archive за дату 2020-01-01
:
ИЗМЕНИТЬ ИЗМЕНИТЬ КОЛОНКУ на тип JSON
Возможно изменить существующую таблицу и изменить тип колонки на новый тип JSON
. В настоящее время поддерживается только ALTER
из типа String
.
Пример
Сравнение между значениями типа JSON
JSON-объекты сравниваются аналогично картам.
Например:
Примечание: когда 2 пути содержат значения разных типов данных, они сравниваются в соответствии с правилом сравнения типа Variant
.
Советы по лучшему использованию типа JSON
Перед созданием колонки JSON
и загрузкой данных в нее, рассмотрите следующие советы:
- Исследуйте свои данные и укажите как можно больше подсказок путей с типами. Это сделает хранение и чтение гораздо более эффективными.
- Подумайте о том, какие пути вам будут нужны и какие пути вам никогда не понадобятся. Укажите пути, которые вам не понадобятся, в разделе
SKIP
, а в разделеSKIP REGEXP
, если необходимо. Это улучшит хранение. - Не устанавливайте параметр
max_dynamic_paths
на очень высокие значения, так как это может сделать хранение и чтение менее эффективными. Хотя это во многом зависит от параметров системы, таких как память, процессор и т. д., общее правило состоит в том, чтобы не устанавливатьmax_dynamic_paths
> 10 000.