メインコンテンツまでスキップ
メインコンテンツまでスキップ

JSON データ型

Beta feature. Learn more.

JSON 型は、JavaScript オブジェクトノーテーション (JSON) ドキュメントを単一カラムに格納します。

注記

この機能はベータ版であり、まだ本番環境では使用できません。 JSON ドキュメントを扱う必要がある場合は、代わりに こちらのガイド を参照してください。

JSON 型を使用したい場合や、このページの例のためには、以下のように設定してください:

JSON 型のカラムを宣言するには、次の構文を使用できます:

上記の構文のパラメータは以下のように定義されています:

パラメータ説明デフォルト値
max_dynamic_paths単一のデータブロックに格納されるサブカラムとして別々に格納できるパスの数を示すオプションのパラメータ(例えば、MergeTree テーブルの単一データパートに対して)。

この制限を超える場合、他のすべてのパスは単一構造にまとめて格納されます。
1024
max_dynamic_types単一のパスカラムに格納できる異なるデータ型の数を示す、1 から 255 のオプションのパラメータ(例えば、MergeTree テーブルの単一データパートに対して)。

この制限を超える場合、新しいタイプはすべて String 型に変換されます。
32
some.path TypeNameJSON 内の特定のパスのためのオプションの型ヒント。このようなパスは常に指定された型のサブカラムとして格納されます。
SKIP path.to.skipJSON パース中にスキップすべき特定のパスに対するオプションのヒント。このようなパスは JSON カラムに格納されることはありません。指定したパスがネストされた JSON オブジェクトの場合、全体のネストされたオブジェクトがスキップされます。
SKIP REGEXP 'path_regexp'JSON パース中にパスをスキップするために使用されるオプションの正規表現付きヒント。この正規表現に一致するすべてのパスは JSON カラムに格納されることはありません。

JSONの作成

このセクションでは、JSON を作成するためのさまざまな方法を見ていきます。

テーブルカラム定義での JSON の使用

::JSON を使用したキャスト

特別な構文 ::JSON を使って、さまざまなタイプをキャストすることができます。

String から JSON へのキャスト

Tuple から JSON へのキャスト

Map から JSON へのキャスト

廃止されている Object('json') から JSON へのキャスト

注記

JSON パスはフラットに保存されます。つまり、パス a.b.c のようにフォーマットされた JSON オブジェクトから構築すべきかどうかを判断することは不可能です。 私たちの実装は常に後者を仮定します。

例えば:

は次のように返されます:

ではなく

JSON パスをサブカラムとして読み取る

JSON 型は、すべてのパスを別々のサブカラムとして読むことをサポートします。 要求されたパスの型が JSON 型宣言で指定されていない場合、そのパスのサブカラムは常に Dynamic 型になります。

例:

リクエストされたパスがデータ内で見つからなかった場合、その値には NULL が設定されます:

返されたサブカラムのデータ型を確認してみましょう:

見ることができるように、a.b の型は、JSON 型宣言で指定した通り UInt32 であり、他のすべてのサブカラムの型は Dynamic です。

Dynamic 型を持つサブカラムは、特別な構文 json.some.path.:TypeName を使用して読み取ることもできます:

Dynamic サブカラムは任意のデータ型にキャストすることができます。この場合、Dynamic 内部の型をリクエストされた型にキャストできない場合は、例外がスローされます:

JSON サブオブジェクトをサブカラムとして読み取る

JSON 型は、特別な構文 json.^some.path を使用して、タイプ JSON を持つネストされたオブジェクトをサブカラムとして読み取ることをサポートします:

注記

サブオブジェクトをサブカラムとして読み取ることは非効率である可能性があります。これは、JSON データ全体をスキャンする必要があるためです。

パスの型推論

JSON のパース中に、ClickHouse は各 JSON パスの最も適切なデータ型を検出しようとします。 これは、入力データからの自動スキーマ推論 と同様に動作し、同じ設定によって制御されます:

いくつかの例を見てみましょう:

JSON オブジェクトの配列の処理

オブジェクトの配列を含む JSON パスは、 Array(JSON) 型として解析され、パスの Dynamic カラムに挿入されます。 オブジェクトの配列を読み取るためには、 Dynamic カラムからサブカラムとして抽出することができます:

気づかれたかもしれませんが、ネストされた JSON 型の max_dynamic_types / max_dynamic_paths パラメータはデフォルト値に比べて減少しています。 これは、ネストされた 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 オブジェクトの解析中に、現在のデータブロックの制限に達した場合、すべての新しいパスは共有データ構造に格納されます。次の2つのイントロスペクション関数 JSONDynamicPaths, JSONSharedDataPaths を使用できます:

見ることができるように、パス ef.g を挿入した後に制限に達し、それらは共有データ構造に挿入されました。

MergeTree テーブルエンジンにおけるデータパーツのマージ中

MergeTree テーブル内の複数のデータパーツをマージする際、生成されたデータパート内の JSON カラムは動的パスの制限に達し、ソースパーツからのすべてのパスをサブカラムとして格納できなくなることがあります。この場合、ClickHouse はマージ後にどのパスがサブカラムとして残るか、どのパスが共有データ構造に格納されるかを選択します。ほとんどのケースにおいて、ClickHouse は非 NULL 値が最も多いパスを保持し、最も稀なパスを共有データ構造に移動しようとします。ただし、これは実装によって異なる場合があります。

このようなマージの例を見てみましょう。まず、JSON カラムがあり、動的パスの制限を 3 に設定したテーブルを作成し、5 つの異なるパスで値を挿入します:

各挿入は、単一のパスを含む JSON カラムを持つ別々のデータパートを作成します:

次に、すべてのパーツを1つにマージし、何が起こるか見てみましょう:

見ての通り、ClickHouse は最も頻繁に使用されるパス abc を保持し、パス d および e を共有データ構造に移動しました。

インストロpection 関数

JSON カラムの内容を検査するためのいくつかの関数があります:

GH Archive データセットの 2020-01-01 日付の内容を調査しましょう:

ALTER MODIFY COLUMN を JSON 型に変更

既存のテーブルを変更し、カラムの型を新しい JSON 型に変更することが可能です。現在、String 型からの ALTER のみがサポートされています。

JSON 型の値の比較

JSON カラムの値は less/greater 関数で比較することはできませんが、equal 関数を使用して比較することができます。

2つの JSON オブジェクトは、同じパスのセットを持ち、これらのパスのそれぞれが両方のオブジェクトで同じ型と値を持つ場合に等しいと見なされます。

例えば:

JSON 型のより良い使用のためのヒント

JSON カラムを作成し、データをロードする前に、以下のヒントを考慮してください:

  • データを調査し、できるだけ多くのパスヒントと型を指定してください。これにより、ストレージと読み取りがより効率的になります。
  • どのパスが必要で、どのパスが必要ないかを考慮してください。必要ないパスを SKIP セクションおよび必要に応じて SKIP REGEXP セクションに指定してください。これによりストレージが改善されます。
  • max_dynamic_paths パラメータを非常に高い値に設定しないでください。これはストレージと読み取りを非効率的にする可能性があります。システムパラメータ(メモリ、CPU など)に大きく依存しますが、一般的な目安として max_dynamic_paths > 10,000 にしないことをお勧めします。

さらなる読み物