# 機能設計書 27-JSONファイルサポート

## 概要

本ドキュメントは、Apache SparkにおけるJSONファイルの読み込み・書き出し機能の設計について記述する。ネストした構造のスキーマ推論に対応し、半構造化データの効率的な処理を提供する。

### 本機能の処理概要

SparkのJSONサポートは、JSON（JavaScript Object Notation）形式のデータファイルの読み込みと書き出しを提供する。Jackson JSONパーサーライブラリを基盤として、JSONLines形式（1行1レコード）およびマルチラインJSON形式の解析に対応する。ネストしたオブジェクトや配列構造のスキーマ推論機能により、複雑な半構造化データをSpark SQLのStructType/ArrayType/MapTypeとして表現できる。

**業務上の目的・背景**：JSONはWebAPI、ログデータ、NoSQLデータベース等で広く使用される半構造化データフォーマットである。SparkのJSONサポートにより、これらのデータソースからのデータをSpark SQLの構造化データとして効率的に処理できる。ネストした構造体の自動スキーマ推論は、スキーマが事前に定義されていないデータの探索的分析に有用である。

**機能の利用シーン**：WebAPIレスポンスデータの分析、アプリケーションログの構造化解析、NoSQLデータベースからのデータ取り込み、IoTセンサーデータの処理。

**主要な処理内容**：
1. JSONファイルの読み込み（JacksonParser使用）
2. ネスト構造のスキーマ推論（JsonInferSchema使用）
3. JSONファイルの書き出し（JacksonGenerator使用）
4. フィルタプッシュダウン（JsonFilters使用）
5. 多様なJSON設定への対応（日付/タイムスタンプフォーマット等）
6. マルチラインJSON対応
7. 破損レコードの処理

**関連システム・外部連携**：Jackson JSONライブラリ（jackson-core）、Hadoop FileSystem API

**権限による制御**：ファイルシステムのアクセス権限に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接関連する画面なし |

## 機能種別

データ連携 / ファイルI/O / データ変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | String | Yes | JSONファイルパス | 有効なファイルシステムパス |
| multiLine | Boolean | No | マルチラインJSON（デフォルト: false） | true/false |
| primitivesAsString | Boolean | No | プリミティブ型を文字列として読み込み | true/false |
| allowComments | Boolean | No | JSONコメントの許可 | true/false |
| allowUnquotedFieldNames | Boolean | No | 引用符なしフィールド名の許可 | true/false |
| dateFormat | String | No | 日付フォーマット | 有効な日付パターン |
| timestampFormat | String | No | タイムスタンプフォーマット | 有効なタイムスタンプパターン |
| mode | String | No | パースモード（PERMISSIVE/DROPMALFORMED/FAILFAST） | 列挙値 |
| columnNameOfCorruptRecord | String | No | 破損レコード格納カラム名 | 有効なカラム名 |
| encoding | String | No | 文字エンコーディング | 有効なエンコーディング名 |

### 入力データソース

- Hadoop互換ファイルシステム上のJSONファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| DataFrame | Dataset[Row] | 読み込まれたJSONデータ（ネスト構造対応） |

### 出力先

- DataFrame/Dataset（読み取り結果）
- Hadoop互換ファイルシステム上のJSONファイル（書き出し結果）

## 処理フロー

### 処理シーケンス

```
1. JSONOptions解析
   └─ パラメータをJSONOptionsオブジェクトで管理
2. スキーマ決定
   └─ ユーザー指定スキーマまたはJsonInferSchemaによるネスト構造推論
3. データ解析
   └─ JacksonParserによるJSON行の解析
4. ネスト構造の型変換
   └─ StructType/ArrayType/MapTypeへの変換
5. 書き出し
   └─ JacksonGeneratorによるJSON行の生成
```

### フローチャート

```mermaid
flowchart TD
    A[spark.read.json] --> B[JSONOptions解析]
    B --> C{スキーマ指定?}
    C -->|Yes| D[ユーザースキーマ適用]
    C -->|No| E[JsonInferSchema]
    D --> F[JacksonParser]
    E --> F
    F --> G{multiLine?}
    G -->|Yes| H[ファイル全体をJSONとして解析]
    G -->|No| I[1行1JSONとして解析]
    H --> J{パースエラー?}
    I --> J
    J -->|PERMISSIVE| K[破損レコード格納]
    J -->|FAILFAST| L[例外スロー]
    J -->|No| M[DataFrame]
    K --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-27-01 | ネスト推論 | JSONオブジェクトはStructType、配列はArrayTypeとして推論 | スキーマ推論時 |
| BR-27-02 | 型マージ | 異なるスキーマのレコードが混在する場合、スキーマをマージ | スキーマ推論時 |
| BR-27-03 | パースモード | PERMISSIVE/DROPMALFORMED/FAILFASTの3モード | 読み込み時 |
| BR-27-04 | デフォルト形式 | JSONLines形式（1行1レコード）がデフォルト | multiLine=false時 |

### 計算ロジック

JsonInferSchemaはサンプリングされたJSONレコードからスキーマを推論する。ネストしたオブジェクトは再帰的にStructTypeに変換され、配列はArrayTypeに変換される。型の競合がある場合は、より広い型にキャストされる（例：IntegerType と LongType → LongType）。

## データベース操作仕様

### 操作別データベース影響一覧

本機能はファイルシステム上のJSONファイルを対象とし、直接的なデータベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| JSON_PARSE_ERROR | パースエラー | 不正なJSON構文 | mode設定に応じた処理 |
| SCHEMA_INFERENCE_EMPTY | 推論エラー | 空のJSONファイル | スキーマの明示的指定 |
| ENCODING_ERROR | エンコーディングエラー | 不正な文字エンコーディング | encoding設定の確認 |

### リトライ仕様

ファイル読み取りの失敗はタスクレベルでリトライされる。

## トランザクション仕様

書き出し時はFileOutputCommitterによるコミットプロトコルが適用される。

## パフォーマンス要件

- Jackson ストリーミングAPIによる効率的なJSON解析
- スキーマ推論はデータのサンプリングスキャンが必要
- multiLine=falseの場合は行単位の並列処理が可能

## セキュリティ考慮事項

- ファイルシステムのアクセス権限に依存
- JSONインジェクション対策は出力時のJacksonGeneratorで適切にエスケープ

## 備考

- SparkのJSON解析にはJacksonライブラリが使用されている
- from_json()/to_json()関数によるカラム内のJSON変換も利用可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | JSONOptions.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JSONOptions.scala` | JSONオプション定義、パラメータ管理 |

#### Step 2: パーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | JacksonParser.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonParser.scala` | Jackson StreamingAPIを使用したJSON解析 |
| 2-2 | CreateJacksonParser.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/CreateJacksonParser.scala` | Jacksonパーサーファクトリ |
| 2-3 | JsonInferSchema.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JsonInferSchema.scala` | ネスト構造のスキーマ推論 |

#### Step 3: ジェネレーターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JacksonGenerator.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonGenerator.scala` | JSON行の生成ロジック |

#### Step 4: フィルタを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | JsonFilters.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JsonFilters.scala` | JSONデータへのフィルタ適用 |
| 4-2 | JacksonUtils.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonUtils.scala` | Jacksonユーティリティ |

### プログラム呼び出し階層図

```
DataFrameReader.json()
    │
    ├─ JSONFileFormat (V1)
    │      ├─ inferSchema() → JsonInferSchema
    │      ├─ prepareWrite()
    │      └─ buildReader()
    │             ├─ JSONOptions解析
    │             ├─ CreateJacksonParser
    │             └─ JacksonParser
    │                    └─ Jackson StreamingAPI
    │
    └─ JSONDataSourceV2 (V2)
           └─ JsonScanBuilder → JsonPartitionReaderFactory
```

### データフロー図

```
[入力]                    [処理]                              [出力]

JSONファイル ─────────▶ JSONOptions解析 ──────────▶ JacksonParser
(テキスト)               │                           │
                        └─ スキーマ推論              ├─ ネスト構造変換
                           (JsonInferSchema)         └─ エラーハンドリング
                                                          │
                                                          ▼
                                                    DataFrame

DataFrame ──────────▶ JacksonGenerator ──────────▶ JSONファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JSONOptions.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JSONOptions.scala` | ソース | JSONオプション定義 |
| JacksonParser.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonParser.scala` | ソース | JSON解析エンジン |
| JsonInferSchema.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JsonInferSchema.scala` | ソース | スキーマ推論 |
| JacksonGenerator.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonGenerator.scala` | ソース | JSON生成エンジン |
| JsonFilters.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JsonFilters.scala` | ソース | フィルタ適用 |
| CreateJacksonParser.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/CreateJacksonParser.scala` | ソース | パーサーファクトリ |
| JacksonUtils.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/json/JacksonUtils.scala` | ソース | ユーティリティ |
