JSON ドライバー: 階層データの解析
最近のサービスでは、データを JSON オブジェクト、配列、またはそれらの組み合わせとして返却・保存することが一般的です。これは階層データの保存には便利ですが、一般的な BI、レポーティング、ETL ツールで扱うには少し工夫が必要です。ネストした JSON データを扱うには、主に以下の2つの手法があります。
- 水平・垂直フラット化を使用して、ネストした配列やオブジェクトにドリルダウンする方法
- データ構造を解析し、既存の階層に基づいてリレーショナルモデルを構築する方法
この記事では、これら2つの手法の違いと、ドライバーでどちらの手法を使用するかを設定する方法について説明します。別のナレッジベース記事では、水平・垂直フラット化を使用した JSON データの解釈方法についてより詳しく解説しています。
Document、Flattened Documents、Relational モデリング
CData JSON ドライバーは、完全なドキュメントのレポート、暗黙的に JOIN されたフラット化ドキュメント、またはリレーショナルモデルの構築によって NoSQL データを管理します。完全なドキュメントをレポートする場合、ドライバーはネストしたオブジェクト配列を集約された JSON オブジェクトとして返します。フラット化ドキュメントを扱う場合、ドライバーはネストした配列オブジェクトを単一のテーブルとして解釈し、SELECT クエリを実行することで暗黙的に JOIN を実行できます。リレーショナルモデルを構築する場合、ドライバーは検出されたオブジェクトと構造に基づいて結果を個別のテーブルとして解釈し、NoSQL データのリレーショナルモデルを表示して、明示的な SQL JOIN クエリを実行できます。以下に各手法の例を示します。
- Document: NoSQL データのトップレベルのドキュメントビュー。集約された配列を含みます。
- Flattened Documents: ネストした配列オブジェクトが親オブジェクトに暗黙的に JOIN されます。
- Relational Modeling: すべての NoSQL データを個別のテーブルとして表示します。
参考として、これらの例は以下のサンプル JSON ドキュメントに基づいています。
サンプルドキュメント
このサンプルドキュメントには、人物、所有する車両、およびそれらの車両に対して行われたさまざまなメンテナンスサービスのエントリが含まれています。
people.json
{
"people": [
{
"personal": {
"age": 20,
"gender": "M",
"name": {
"first": "John",
"last": "Doe"
}
},
"vehicles": [
{
"type": "car",
"model": "Honda Civic",
"insurance": {
"company": "ABC Insurance",
"policy_num": "12345"
},
"maintenance": [
{
"date": "07-17-2017",
"desc": "oil change"
},
{
"date": "01-03-2018",
"desc": "new tires"
}
]
},
{
"type": "truck",
"model": "Dodge Ram",
"insurance": {
"company": "ABC Insurance",
"policy_num": "12345"
},
"maintenance": [
{
"date": "08-27-2017",
"desc": "new tires"
},
{
"date": "01-08-2018",
"desc": "oil change"
}
]
}
],
"source": "internet"
},
{
"personal": {
"age": 24,
"gender": "F",
"name": {
"first": "Jane",
"last": "Roberts"
}
},
"vehicles": [
{
"type": "car",
"model": "Toyota Camry",
"insurance": {
"company": "Car Insurance",
"policy_num": "98765"
},
"maintenance": [
{
"date": "05-11-2017",
"desc": "tires rotated"
},
{
"date": "11-03-2017",
"desc": "oil change"
}
]
},
{
"type": "car",
"model": "Honda Accord",
"insurance": {
"company": "Car Insurance",
"policy_num": "98765"
},
"maintenance": [
{
"date": "10-07-2017",
"desc": "new air filter"
},
{
"date": "01-13-2018",
"desc": "new brakes"
}
]
}
],
"source": "phone"
}
]
}
Document モデリング
NoSQL データのトップレベルのドキュメントビューを使用すると、階層的な配列を処理・解析するための時間とリソースを節約しながら、トップレベルのフィールドとオブジェクトに簡単にアクセスできます。CData ドライバーは、最上位の繰り返し要素に基づいて JSON ストアを表示し、すべてのネストした配列を単一のカラムとして扱うように設定できます。このモードでは、ドライバーはストリーミングを使用して JSON データを読み取り、クエリごとに返されたデータを1回だけ解析します。
以下は、上記のサンプルドキュメントに基づいたサンプルクエリとその結果です。このクエリは、JSON パス "$.people" に基づいて単一の "people" テーブルを生成します。
接続文字列
Data Model 接続プロパティを "Document" に設定し、JSON Path 接続プロパティを "$.people" に設定すると、上記のクエリを実行してサンプル結果セットを確認できます。
DataModel=Document;JSONPath='$.people';
メタデータ
以下のテーブルは、Document データモデルを使用した場合のメタデータを示しています。
| People | |
|---|---|
| カラム | データ型 |
| personal.age | Integer |
| personal.gender | String |
| personal.name.first | String |
| personal.name.last | String |
| source | String |
| vehicles | String |
クエリ
このクエリでは、トップレベルのオブジェクト要素と配列を結果に取り込みます。トップレベルのオブジェクト要素は、デフォルトのオブジェクトフラット化により利用可能です。配列は集約された JSON として返されます。
SELECT [personal.age] AS age, [personal.gender] AS gender, [personal.name.first] AS name_first, [personal.name.last] AS name_last, [source], [vehicles] FROM [people]
結果
データのドキュメントビューでは、"personal" オブジェクトが4つのカラムにフラット化され、"source" と "vehicles" 要素がそれぞれ個別のカラムとして返され、結果として6つのカラムを持つテーブルになります。
| age | gender | name_first | name_last | source | vehicles |
|---|---|---|---|---|---|
| 20 | M | John | Doe | internet | [{"type":"car","model":"Honda Civic","insurance":{"company":"ABC Insurance","policy_num":"12345"},"maintenance":[{"date":"07-17-2017","desc":"oil change"},{"date":"01-03-2018","desc":"new tires"}]},{"type":"truck","model":"Dodge Ram","insurance":{"company":"ABC Insurance","policy_num":"12345"},"maintenance":[{"date":"08-27-2017","desc":"new tires"},{"date":"01-08-2018","desc":"oil change"}]}] |
| 24 | F | Jane | Roberts | phone | [{"type":"car","model":"Toyota Camry","insurance":{"company":"Car Insurance","policy_num":"98765"},"maintenance":[{"date":"05-11-2017","desc":"tires rotated"},{"date":"11-03-2017","desc":"oil change"}]},{"type":"car","model":"Honda Accord","insurance":{"company":"Car Insurance","policy_num":"98765"},"maintenance":[{"date":"10-07-2017","desc":"new air filter"},{"date":"01-13-2018","desc":"new brakes"}]}] |
メリットと考慮事項
Document モデルを使用すると、JSON ストアまたはサービスのすべてのトップレベルデータと集約された配列データを単一のテーブルで確認できます。シンプルなクエリを送信してトップレベルデータを操作できます。クエリごとに JSON データの読み取りと解析のリクエストが1回だけ実行されるため、高速なパフォーマンスとストリーミング機能との優れた互換性が得られます。考慮すべき点としては、配列に格納されているデータへのニーズと、お使いのツールやアプリケーションが JSON 配列を意味のある形で処理できるかどうかがあります。
Flattened Documents モデリング
JSON データ全体に簡単にアクセスしたいユーザーには、データを単一のテーブルにフラット化するのが最適な選択肢です。JSON データ内の JSON パスに基づいて、ドライバーを単一のテーブルを解析するように設定できます。このモードでは、ネストしたオブジェクト配列は別のテーブルとして扱われますが、親テーブルに暗黙的に JOIN されます。ドライバーはストリーミングを使用し、クエリごとに JSON データを1回だけ解析します。Flattened Documents モデルでは、ドット表記を使用して JSON データ内のネストした要素にドリルダウンすることで、データに対して暗黙的な JOIN 文を実行できます。
以下は、上記のサンプルドキュメントに基づいたサンプルクエリとその結果です。JSON パス "$.people"、"$.people.vehicles"、"$.people.vehicles.maintenance" に基づいて解析します(これにより "people" コレクションと "vehicles" コレクションが暗黙的に JOIN され、"vehicles" コレクションと "maintenance" コレクションが暗黙的に JOIN されます)。
接続文字列
Data Model 接続プロパティを "FlattenedDocuments" に設定し、JSON Path 接続プロパティを "$.people;$.people.vehicles;$.people.vehicles.maintenance;" に設定すると、上記のクエリを実行してサンプル結果セットを確認できます。
DataModel=FlattenedDocuments;JSONPath='$.people;$.people.vehicles;$.people.vehicles.maintenance;'
メタデータ
以下のテーブルは、Flattened Documents データモデルを使用した場合のメタデータを示しています。
| People | |
|---|---|
| カラム | データ型 |
| people:_id | String |
| personal.age | Integer |
| personal.gender | String |
| personal.name.first | String |
| personal.name.last | String |
| source | String |
| vehicle:_id | String |
| type | String |
| model | String |
| insurance.company | String |
| insurance.policy_num | String |
| maintenance:_id | String |
| date | Date |
| desc | String |
クエリ
このクエリでは、各 "people" オブジェクト内のネストした要素にドリルダウンできます。"vehicles" コレクションを JSON パスとして含めたので、"vehicle" の要素を明示的にクエリできます。
SELECT [personal.age] AS age, [personal.gender] AS gender, [personal.name.first] AS name_first, [personal.name.last] AS name_last, [source], [type], [model], [insurance.company] AS ins_company, [insurance.policy_num] AS ins_policy_num, [date] AS maint_date, [desc] AS maint_desc FROM [people]
結果
記述されたパスに基づく水平・垂直フラット化により、各 "vehicle" オブジェクトはその親 "people" オブジェクトに暗黙的に JOIN され、各 "maintenance" オブジェクトはその親 "vehicle" オブジェクトに暗黙的に JOIN されます。結果として8行のテーブルが生成されます(2人の "people" それぞれに対して2つの "vehicles"、各 "vehicle" に対して2つの "maintenance" オブジェクト)。
| age | gender | first_name | last_name | source | type | model | ins_company | ins_policy_num | maint_date | maint_desc |
|---|---|---|---|---|---|---|---|---|---|---|
| 20 | M | John | Doe | internet | car | Honda Civic | ABC Insurance | 12345 | 2017-07-17 | oil change |
| 20 | M | John | Doe | internet | car | Honda Civic | ABC Insurance | 12345 | 2018-01-03 | new tires |
| 20 | M | John | Doe | internet | truck | Dodge Ram | ABC Insurance | 12345 | 2017-08-27 | new tires |
| 20 | M | John | Doe | internet | truck | Dodge Ram | ABC Insurance | 12345 | 2018-01-08 | oil change |
| 24 | F | Jane | Roberts | phone | car | Toyota Camry | Car Insurance | 98765 | 2017-05-11 | tires rotated |
| 24 | F | Jane | Roberts | phone | car | Toyota Camry | Car Insurance | 98765 | 2017-11-03 | oil change |
| 24 | F | Jane | Roberts | phone | car | Honda Accord | Car Insurance | 98765 | 2017-10-07 | new air filter |
| 24 | F | Jane | Roberts | phone | car | Honda Accord | Car Insurance | 98765 | 2018-01-13 | new brakes |
メリットと考慮事項
Flattened Documents を使用すると、JSON ストアまたはサービスのすべてのデータを単一のテーブルで確認できます。シンプルなクエリを送信して階層データにドリルダウンできます。クエリごとに JSON データの読み取りと解析のリクエストが1回だけ実行されるため、高速なパフォーマンスとストリーミング機能との優れた互換性が得られます。Flattened Documents を使用する際は、お使いのツールやアプリケーションが、個別のエンティティと事前に JOIN されたデータセットのどちらとより相性が良いかを考慮する必要があります。
Relational モデリング
CData ドライバーは、JSON ファイルまたはソース内のデータのリレーショナルモデルを作成するように設定でき、ネストしたオブジェクト配列を親テーブルとのリレーションシップを含む個別のテーブルとして扱います。これは、リレーショナルデータモデルを前提とする既存の BI、レポーティング、ETL ツールで JSON データを操作する必要がある場合に特に便利です。解釈されるモデルは、テーブルとして表示したい各オブジェクト配列のデータ内の JSON パスに基づいています。リレーショナルモデルを構築すると、JOIN クエリを実行するたびに、クエリに含まれる各「テーブル」に対して JSON ファイルまたはソースが1回ずつクエリされます。
以下は、上記のサンプルドキュメントに基づいたサンプルクエリとその結果です。JSON パス "$.people"、"$.people.vehicles"、"$.people.vehicles.maintenance" に基づくリレーショナルモデルを使用しています。
接続文字列
Data Model 接続プロパティを "Relational" に設定し、JSON Path 接続プロパティを "$.people;$.people.vehicles;$.people.vehicles.maintenance;" に設定すると、上記のクエリを実行してサンプル結果セットを確認できます。
DataModel=Relational;JSONPath='$.people;$.people.vehicles;$.people.vehicles.maintenance;'
メタデータ
以下のテーブルは、Relational データモデルを使用した場合のメタデータを示しています。
| People | |
|---|---|
| カラム | データ型 |
| _id | String |
| personal.age | Integer |
| personal.gender | String |
| personal.name.first | String |
| personal.name.last | String |
| source | String |
| Vehicles | |
|---|---|
| カラム | データ型 |
| _id | String |
| insurance.company | String |
| insurance.policy_num | String |
| model | String |
| type | String |
| Maintenance | |
|---|---|
| カラム | データ型 |
| _id | String |
| date | Date |
| desc | String |
クエリ
このクエリでは、"people"、"vehicles"、"maintenance" テーブルを明示的に JOIN しています。
SELECT [people].[personal.age] AS age, [people].[personal.gender] AS gender, [people].[personal.name.first] AS first_name, [people].[personal.name.last] AS last_name, [people].[source], [vehicles].[type], [vehicles].[model], [vehicles].[insurance.company] AS ins_company, [vehicles].[insurance.policy_num] AS ins_policy_num, [maintenance].[date] AS maint_date, [maintenance].[desc] AS maint_desc FROM [people] JOIN [vehicles] ON [people].[_id] = [vehicles].[people_id] JOIN [maintenance] ON [vehicles].[_id] = [maintenance].[vehicles_id]
結果
リレーショナルモデルを使用すると、JOIN はすべてクエリによって制御されます。この例では、各 "maintenance" オブジェクトがその親 "vehicle" オブジェクトに JOIN され、さらにその親 "people" オブジェクトに JOIN されて8行のテーブルが生成されます(2人の "people" それぞれに対して2つの "vehicles"、各 "vehicle" に対して2つの "maintenance" エントリ)。
| age | gender | first_name | last_name | source | type | model | ins_company | ins_policy_num | maint_date | maint_desc |
|---|---|---|---|---|---|---|---|---|---|---|
| 20 | M | John | Doe | internet | car | Honda Civic | ABC Insurance | 12345 | 2017-07-17 | oil change |
| 20 | M | John | Doe | internet | car | Honda Civic | ABC Insurance | 12345 | 2018-01-03 | new tires |
| 20 | M | John | Doe | internet | truck | Dodge Ram | ABC Insurance | 12345 | 2017-08-27 | new tires |
| 20 | M | John | Doe | internet | truck | Dodge Ram | ABC Insurance | 12345 | 2018-01-08 | oil change |
| 24 | F | Jane | Roberts | phone | car | Toyota Camry | Car Insurance | 98765 | 2017-05-11 | tires rotated |
| 24 | F | Jane | Roberts | phone | car | Toyota Camry | Car Insurance | 98765 | 2017-11-03 | oil change |
| 24 | F | Jane | Roberts | phone | car | Honda Accord | Car Insurance | 98765 | 2017-10-07 | new air filter |
| 24 | F | Jane | Roberts | phone | car | Honda Accord | Car Insurance | 98765 | 2018-01-13 | new brakes |
メリットと考慮事項
Relational モデリングを使用すると、JSON データまたはサービス内の個別のエンティティに基づいてデータのモデルを構築でき、一部の BI、レポーティング、ETL ツールとの互換性が向上します。ただし、リレーショナルモデルを構築してクエリを実行するには、パフォーマンスを犠牲にする必要があります。リレーショナルモデル内の複数のテーブルからデータを操作する場合、ドライバーはクエリ内の各テーブルに対してデータのクエリと解析を実行します。たとえば、上記のクエリには3回のリクエストが必要です。
関連記事
- CData NoSQL の概要 - NoSQL を扱う際の CData ドライバー技術の特徴について紹介します。
- NoSQL ドライバー: パフォーマンス比較 - NoSQL データソースから大規模なデータセットをクエリおよび処理する際の、各ベンダーのドライバーのパフォーマンスを比較します。
- NoSQL ドライバー: 機能比較 - NoSQL データソースからの複雑なクエリや複雑なデータセットの処理について、各ベンダーのドライバーを比較します。