# 機能設計書 96-REPL

## 概要

本ドキュメントは、Apache SparkのREPL（Read-Eval-Print Loop）機能の設計について記述する。Spark Shellとして対話的にScalaコードを実行し、SparkContext/SparkSessionを利用した分散処理を即座に試すことができるインタラクティブ環境を提供する。

### 本機能の処理概要

**業務上の目的・背景**：データ探索やプロトタイピングにおいて、コードを即座に実行して結果を確認できる対話的環境は生産性向上に不可欠である。Spark REPLは、ScalaのインタープリタをSpark環境に統合し、spark（SparkSession）とsc（SparkContext）を自動的に初期化して提供する。

**機能の利用シーン**：`spark-shell` コマンドで起動し、対話的にSparkジョブを実行するアドホック分析、データ探索、機能テスト、学習目的で利用される。

**主要な処理内容**：
1. Main.mainによるエントリーポイント：設定解析とSparkILoopの起動
2. SparkILoopによるScalaインタープリタの統合と初期化コマンドの実行
3. SparkSessionの自動生成（Hiveサポート自動検出含む）
4. 対話的なR.E.P.Lループの実行
5. :resetコマンドでの状態リセットとSpark再初期化

**関連システム・外部連携**：Scala NSCコンパイラ（scala.tools.nsc）に依存。SparkSession/SparkContextとの統合。Hiveメタストアとの自動接続（Hiveクラスが利用可能な場合）。

**権限による制御**：SparkContextの権限に依存。REPLクラスローダー用の一時ディレクトリを使用。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに本機能に対応する画面定義なし |

## 機能種別

ユーティリティ / 対話型実行環境

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| args | Array[String] | No | コマンドライン引数 | GenericRunnerSettingsで解析 |
| spark.repl.classdir | String | No | REPLクラス出力ディレクトリ | 有効なディレクトリパス |
| spark.app.name | String | No | アプリケーション名（デフォルト: "Spark shell"） | - |
| CATALOG_IMPLEMENTATION | String | No | カタログ実装（デフォルト: "hive"） | "hive" or "in-memory" |

### 入力データソース

標準入力（対話モード）またはスクリプトファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 評価結果 | 標準出力 | Scala式の評価結果 |
| spark | SparkSession | 自動生成されたSparkSessionインスタンス |
| sc | SparkContext | 自動生成されたSparkContextインスタンス |

### 出力先

標準出力、REPLクラス出力ディレクトリ

## 処理フロー

### 処理シーケンス

```
1. Main.main(args)
   a. isShellSession = true
   b. GenericRunnerSettingsで引数解析
   c. SparkILoop(settings) インスタンス生成
   d. doMain(args, interp) 呼び出し

2. Main.doMain(args, interp)
   a. ユーザーJARのクラスパス設定
   b. インタープリタ引数の構築:
      - -Yrepl-class-based
      - -Yrepl-outdir=${outputDir}
      - -classpath ${jars}
   c. GenericRunnerSettingsで引数処理
   d. interp.run(settings): REPLループ開始

3. SparkILoop.run(settings)
   a. internalReplAutorunCode(): 初期化コマンドの実行
   b. initializationCommands:
      - spark = Main.createSparkSession()
      - sc = spark.sparkContext
      - Web UI URLの表示
      - import文の自動実行
   c. R.E.P.Lループ開始

4. Main.createSparkSession()
   a. SparkConf設定:
      - spark.app.name = "Spark shell"
      - spark.repl.class.outputDir = outputDir
      - spark.sql.artifacts.sessionIsolation.enabled = false
   b. CATALOG_IMPLEMENTATION判定:
      - "hive" + HiveクラスPresent → enableHiveSupport()
      - "hive" + Hiveクラス不在 → "in-memory"にフォールバック
      - その他 → "in-memory"
   c. SparkSession.builder().getOrCreate()

5. REPLリセット (:resetコマンド)
   a. super.resetCommand() → インタープリタリセット
   b. initializeSpark(): spark/sc再初期化
   c. SparkSession/SparkContextの状態は保持される旨を表示
```

### フローチャート

```mermaid
flowchart TD
    A[spark-shell起動] --> B[Main.main]
    B --> C[引数解析]
    C --> D[SparkILoop生成]
    D --> E[doMain: クラスパス設定]
    E --> F[interp.run: REPLループ開始]
    F --> G[初期化コマンド実行]
    G --> H[createSparkSession]
    H --> I{Hiveクラス利用可能?}
    I -->|Yes| J[enableHiveSupport]
    I -->|No| K[in-memoryカタログ]
    J --> L[spark/sc初期化完了]
    K --> L
    L --> M[ウェルカムメッセージ表示]
    M --> N[R.E.P.Lループ]
    N --> O{ユーザー入力}
    O -->|:quit| P[SparkContext.stop]
    O -->|:reset| Q[initializeSpark再実行]
    O -->|Scala式| R[評価・結果表示]
    R --> N
    Q --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-96-01 | Hive自動検出 | Hiveクラスが利用可能ならHiveサポートを有効化 | CATALOG_IMPLEMENTATION="hive" |
| BR-96-02 | セッション分離無効 | REPL環境ではセッション分離を無効化（クラスローダー問題回避） | 常時 |
| BR-96-03 | ウェルカムメッセージ | Spark ASCIIアートとバージョン情報を表示 | 起動時 |
| BR-96-04 | 自動インポート | SparkContext._, spark.implicits._, spark.sql, functions._ を自動インポート | 初期化時 |
| BR-96-05 | リセット時の状態保持 | :resetコマンドでインタープリタをリセットしてもSparkSession/SparkContextは保持 | :reset時 |

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

本機能はデータベースを直接操作しない（ユーザーのSQLコードによるデータベース操作は対象外）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| RuntimeException | 初期化エラー | Scalaインタープリタの初期化でエラー | Scalaバージョン互換性を確認 |
| SparkSession初期化失敗 | 致命的エラー | SparkSession生成失敗（シェルセッション時） | sys.exit(1)で終了。設定を確認 |

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

対話的に実行されるSparkジョブのトランザクション保証に依存。REPL自体のトランザクション管理はない。

## パフォーマンス要件

- クラスベースREPL（-Yrepl-class-based）によるクラス生成方式
- outputDirへのクラスファイル出力で分散実行時のクラスローディングを実現

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

- 一時ディレクトリ（outputDir）へのクラスファイル出力
- SPARK_EXECUTOR_URI環境変数によるエグゼキューター設定
- SPARK_HOME環境変数の使用

## 備考

`repl/` パッケージ配下に実装。Scala NSC（New Scala Compiler）のILoopを拡張。

---

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

### 推奨読解順序

#### Step 1: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Main.scala | `repl/src/main/scala/org/apache/spark/repl/Main.scala` | REPLのエントリーポイント |

**主要処理フロー**:
- **33-49行目**: Mainオブジェクトのフィールド定義。conf, rootDir, outputDir, sparkContext, sparkSession, interp
- **58-63行目**: main()メソッド。isShellSession設定、GenericRunnerSettings処理、SparkILoop生成
- **66-90行目**: doMain()メソッド。JARクラスパス構築、インタープリタ引数設定、interp.run()呼び出し
- **92-141行目**: createSparkSession()メソッド。SparkConf設定、Hive検出分岐、SparkSession/SparkContext初期化

**読解のコツ**: Main.createSparkSession()の条件分岐（112-132行目）を理解するのが重要。CATALOG_IMPLEMENTATION設定とhiveClassesArePresentの組み合わせで3パターンに分岐する。

#### Step 2: SparkILoopを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SparkILoop.scala | `repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala` | Scala ILoopのSpark拡張 |

**主要処理フロー**:
- **34-43行目**: クラス定義とコンストラクタ。ILoopを継承、3つのコンストラクタパターン
- **44-79行目**: initializationCommands。sparkとscの初期化、Web UI表示、import文
- **81-82行目**: internalReplAutorunCode()でinitializationCommandsを返却
- **84-96行目**: initializeSpark()。非エラー時のみ初期化コマンドを実行
- **99-116行目**: printWelcome()。Spark ASCIIアートとバージョン情報の表示
- **121-127行目**: resetCommand()。super.resetCommand() + initializeSpark() + 状態保持メッセージ
- **129-132行目**: replay()。initializeSpark() + super.replay()

**読解のコツ**: initializationCommands（44-79行目）はScalaコードの文字列リストとして定義されており、インタープリタで順次実行される。spark/scの初期化はここで行われ、import文もここに含まれる。

#### Step 3: 静的メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SparkILoop.scala (objectブロック) | `repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala` | **135-158行目**: SparkILoop.run()メソッド。テスト用にコード文字列を直接実行するユーティリティ |

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

```
Main.main(args)
    |
    +-- GenericRunnerSettings.processArguments(args)
    +-- SparkILoop(settings)
    +-- Main.doMain(args, interp)
          |
          +-- Utils.getLocalUserJarsForShell(conf)
          +-- GenericRunnerSettings.processArguments(interpArguments)
          +-- interp.run(settings)
                |
                +-- internalReplAutorunCode() --> initializationCommands
                |     |
                |     +-- Main.createSparkSession()
                |     |     +-- SparkSession.builder()
                |     |     +-- hiveClassesArePresent判定
                |     |     +-- enableHiveSupport() / "in-memory"
                |     |     +-- getOrCreate()
                |     |
                |     +-- spark.sparkContext --> sc
                |     +-- import spark.implicits._ 等
                |
                +-- [R.E.P.Lループ]
                      +-- :reset --> resetCommand()
                      |     +-- super.resetCommand()
                      |     +-- initializeSpark()
                      +-- :quit --> SparkContext.stop()
```

### データフロー図

```
[標準入力]              [SparkILoop]               [Spark Runtime]

ユーザーコード   ──>   Scala NSC Interpreter   ──>   SparkSession
  (Scala式)             (コンパイル+実行)              SparkContext
                              |                         |
                        クラスファイル                 分散ジョブ実行
                        (outputDir)                     |
                              |                    結果取得
                        エグゼキューター              |
                        クラスローディング         標準出力 <──
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Main.scala | `repl/src/main/scala/org/apache/spark/repl/Main.scala` | ソース | REPLエントリーポイント、SparkSession生成 |
| SparkILoop.scala | `repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala` | ソース | Scala ILoopのSpark拡張 |
