# 帳票設計書 15-StagePage

## 概要

本ドキュメントは、Apache Spark Web UI の個別ステージ詳細ページ（StagePage）の帳票設計書である。特定のステージIDと試行番号に対して、タスクメトリクスの統計サマリー、タスクイベントタイムライン、DAG可視化、タスク一覧テーブルをHTML形式で表示する詳細レポートページを定義する。

### 本帳票の処理概要

**業務上の目的・背景**：ステージ内のタスク実行状況を詳細に分析するために必要な帳票である。タスクレベルでのパフォーマンスボトルネック（スケジューラ遅延、GC時間、シャッフル読み書き時間等）を特定し、データスキューやパーティション偏りの問題を発見するために活用される。タスクのタイムライン表示により、各Executor上でのタスク割り当て状況を視覚的に確認できる。

**帳票の利用シーン**：AllStagesPage や JobPage からステージIDをクリックして遷移する場面、特定ステージのタスク実行状況を詳細に確認する場面、データスキューやパーティション偏りを分析する場面、タスクメトリクスの統計分布を確認する場面で利用される。

**主要な出力内容**：
1. ステージサマリー（送信日時、実行時間、リソースプロファイルID、I/O統計、ローカリティ分布）
2. DAG 可視化
3. タスクイベントタイムライン（Executor別タスク割り当て、時間配分の色分け表示）
4. サマリーメトリクス（タスクメトリクスの統計分布）
5. タスク一覧テーブル（ページネーション、ソート対応）

**帳票の出力タイミング**：Spark Web UI で `/stages/stage/?id={stageId}&attempt={attemptId}` にアクセスした際に動的にレンダリングされる。

**帳票の利用者**：アプリケーション開発者、データエンジニア、パフォーマンスチューニング担当者

## 帳票種別

Web UI レポートページ（HTML形式詳細表示）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 15 | Stage Details | `http://{host}:4040/stages/stage/?id={stageId}&attempt={attemptId}` | ステージ一覧からステージIDリンクをクリック |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | HTML（動的レンダリング、DataTables使用） |
| 用紙サイズ | 該当なし（ブラウザ表示） |
| 向き | 該当なし |
| ファイル名 | 該当なし（HTTP レスポンス） |
| 出力方法 | Spark Web UI からのブラウザ表示 |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

```
┌─────────────────────────────────────────┐
│  ページヘッダー                            │
│  (Details for Stage X (Attempt Y))       │
├─────────────────────────────────────────┤
│  ステージサマリー                          │
│  - Submitted / Duration                   │
│  - Resource Profile Id                    │
│  - Total Time Across All Tasks            │
│  - Locality Level Summary                 │
│  - Input/Output Size                      │
│  - Shuffle Read/Write Size                │
│  - Spill (Memory/Disk)                    │
│  - Associated Job Ids                     │
├─────────────────────────────────────────┤
│  DAG Visualization（折りたたみ可能）        │
├─────────────────────────────────────────┤
│  Additional Metrics 表示切替               │
├─────────────────────────────────────────┤
│  Event Timeline（折りたたみ可能）           │
│  - 凡例（時間配分の色分け）                 │
│  - ページネーション                        │
│  - Executor別タスク割り当てチャート          │
├─────────────────────────────────────────┤
│  Summary Metrics / Tasks テーブル          │
│  （stagepage.js で動的レンダリング）         │
└─────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Submitted | ステージ送信日時 | StageDataUtil.getFormattedSubmissionTime | 日時フォーマット |
| 2 | Duration | ステージ実行時間 | StageDataUtil.getFormattedDuration | 時間フォーマット |
| 3 | Resource Profile Id | リソースプロファイルID | stageData.resourceProfileId | 整数 |
| 4 | Total Time Across All Tasks | 全タスクの合計実行時間 | stageData.executorRunTime | 時間フォーマット |
| 5 | Locality Level Summary | ローカリティレベル分布 | store.localitySummary | "Process local: X; Node local: Y" |
| 6 | Input Size / Records | 入力サイズとレコード数 | stageData.inputBytes / inputRecords | バイト表示 / 件数 |
| 7 | Output Size / Records | 出力サイズとレコード数 | stageData.outputBytes / outputRecords | バイト表示 / 件数 |
| 8 | Shuffle Read Size / Records | シャッフル読み取りサイズとレコード数 | stageData.shuffleReadBytes / shuffleReadRecords | バイト表示 / 件数 |
| 9 | Shuffle Write Size / Records | シャッフル書き込みサイズとレコード数 | stageData.shuffleWriteBytes / shuffleWriteRecords | バイト表示 / 件数 |
| 10 | Spill (Memory) | メモリスピル量 | stageData.memoryBytesSpilled | バイト表示 |
| 11 | Spill (Disk) | ディスクスピル量 | stageData.diskBytesSpilled | バイト表示 |
| 12 | Associated Job Ids | 関連ジョブID一覧 | stageJobIds | リンク付きIDリスト |

### 明細部

タスクイベントタイムラインの各タスク要素。

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | Task Index | タスクインデックス | taskInfo.index | 整数 | - |
| 2 | Status | タスクステータス | taskInfo.status | 文字列 | - |
| 3 | Launch Time | タスク開始時刻 | taskInfo.launchTime | 日時 | - |
| 4 | Scheduler Delay | スケジューラ遅延 | AppStatusUtils.schedulerDelay | ミリ秒 | - |
| 5 | Task Deserialization Time | タスクデシリアライズ時間 | metricsOpt.executorDeserializeTime | 時間フォーマット | - |
| 6 | Shuffle Read Time | シャッフル読み取り時間 | shuffleReadMetrics.fetchWaitTime | 時間フォーマット | - |
| 7 | Executor Computing Time | Executor 計算時間 | executorRunTime - overhead | 時間フォーマット | - |
| 8 | Shuffle Write Time | シャッフル書き込み時間 | shuffleWriteMetrics.writeTime | 時間フォーマット | - |
| 9 | Result Serialization Time | 結果シリアライズ時間 | metricsOpt.resultSerializationTime | 時間フォーマット | - |
| 10 | Getting Result Time | 結果取得時間 | AppStatusUtils.gettingResultTime | 時間フォーマット | - |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| - | 該当なし | タスクテーブルは stagepage.js で動的レンダリング | - | - |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| id パラメータ | ステージID | Yes |
| attempt パラメータ | 試行番号 | Yes |
| タイムラインタスク数制限 | MAX_TIMELINE_TASKS で表示タスク数を制限 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | タスクインデックス（デフォルト） | 昇順 |
| 2 | task.sort パラメータで動的変更可能 | 可変 |

### 改ページ条件

タスクイベントタイムラインおよびタスクテーブルにページネーション機能あり。task.eventTimelinePageNumber と task.eventTimelinePageSize で制御。

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| AppStatusStore (KVStore) | ステージ・タスク情報の取得 | stageId, stageAttemptId |

### テーブル別参照項目詳細

#### AppStatusStore

| 参照項目（メソッド） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| stageAttempt(stageId, attemptId, details=false) | ステージデータ + ジョブID | stageId, attemptId | StageData と Set[Int] |
| localitySummary(stageId, attemptId) | ローカリティ分布 | stageId, attemptId | Map[String, Long] |
| taskCount(stageId, attemptId) | 総タスク数 | stageId, attemptId | Long |
| taskList(stageId, attemptId, from, count, sortBy, ascending) | タスクデータ | ページネーション | TaskData のリスト |
| operationGraphForStage(stageId) | DAG 可視化用 | stageId | RDDOperationGraph |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| totalTasks | numActiveTasks + numCompleteTasks + numFailedTasks + numKilledTasks | なし | 0の場合は "No tasks have started yet" 表示 |
| totalExecutionTime | finishTime - launchTime | なし | タイムライン比率計算の基準 |
| Executor Computing Time | executorRunTime - shuffleReadTime - shuffleWriteTime | なし | 正の値になるよう調整 |
| Scheduler Delay | AppStatusUtils.schedulerDelay(taskInfo) | なし | 全体時間からその他の時間を差し引いた残り |
| 各時間配分比率 | time / totalExecutionTime * 100 | なし | SVGバーの幅をパーセントで指定 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[HTTP GET /stages/stage/?id=X&attempt=Y] --> B[StagePage.render]
    B --> C[id, attempt パラメータ検証]
    C --> D[store.stageAttempt 取得]
    D --> E{ステージ存在?}
    E -->|No| F[No information メッセージ]
    E -->|Yes| G[totalTasks 算出]
    G --> H{totalTasks == 0?}
    H -->|Yes| I[No tasks メッセージ]
    H -->|No| J[ステージサマリー生成]
    J --> K[DAG 可視化生成]
    K --> L[makeTimeline でタスクタイムライン生成]
    L --> M[stagepage.js ロード]
    M --> N[HTML レスポンス構成]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| パラメータ不足 | id または attempt パラメータが null/空 | "Missing id/attempt parameter" | 正しいURLでアクセス |
| ステージ未発見 | 指定ステージが存在しない | "No information to display for Stage X (Attempt Y)" | 正しいステージIDを確認 |
| タスク未開始 | totalTasks == 0 | "No tasks have started yet" | タスクが開始されるまで待つ |
| SVGバー幅0 | totalExecutionTime == 0 | 空のSVG要素を表示 | SPARK-8705対応、正常動作 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1ステージあたり数百〜数万タスク |
| 目標出力時間 | 2秒以内 |
| 同時出力数上限 | Web UI 同時接続数に依存 |

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

- スレッドダンプ機能は UI_THREAD_DUMPS_ENABLED 設定で制御される
- タスク情報は HTML エスケープ処理される

## 備考

- タスクテーブルのソートとページネーションは stagepage.js で動的に制御される（REST API経由）
- タイムラインの時間配分は7種類の色で表示される: Scheduler Delay, Task Deserialization, Shuffle Read, Executor Computing, Shuffle Write, Result Serialization, Getting Result
- SPARK-8705: totalExecutionTime が0の場合は空のSVGバーを表示（行331-333）
- SPARK-26109: Duration カラムは executorRunTime を使用してタスクサマリーと整合性を保つ

---

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

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

### 推奨読解順序

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

タスクデータとメトリクスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | v1/api.scala | `core/src/main/scala/org/apache/spark/status/api/v1/api.scala` | TaskData, StageData, ShuffleReadMetrics 等の定義 |
| 1-2 | AppStatusUtils.scala | `core/src/main/scala/org/apache/spark/status/AppStatusUtils.scala` | schedulerDelay, gettingResultTime の計算ロジック |

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

StagePage.render メソッドの処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StagePage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala` | render メソッド（行83-248）のパラメータ処理とデータ取得 |

**主要処理フロー**:
1. **行84-106**: id, attempt, ページネーション等のURLパラメータ解析
2. **行109-117**: store.stageAttempt でステージデータとジョブIDを取得
3. **行121-123**: totalTasks を算出、0の場合は早期リターン
4. **行141-211**: ステージサマリーHTML生成（I/O統計、ローカリティ、関連ジョブ等）
5. **行213-214**: DAG 可視化生成
6. **行227-238**: makeTimeline でタスクタイムライン生成

#### Step 3: タスクタイムライン描画を理解する

各タスクの時間配分計算とSVGバー生成ロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StagePage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala` | makeTimeline（行250-455）のタスクデータ処理と時間配分計算 |

**主要処理フロー**:
- **行269-389**: 各タスクの時間配分計算（7カテゴリ）とSVGバー生成
- **行281-282**: toProportion 関数で時間をパーセンテージに変換
- **行330-357**: SVGバーの各rect要素を位置とサイズで配置

#### Step 4: ApiHelper を理解する

タスクテーブルのカラム定義とソートマッピング。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | StagePage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala` | ApiHelper オブジェクト（行459-559）のヘッダー定義とCOLUMN_TO_INDEX マッピング |

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

```
HttpServletRequest (?id=X&attempt=Y)
    |
    +-- StagePage.render()
            |
            +-- store.stageAttempt(stageId, attemptId)
            +-- store.localitySummary(stageId, attemptId)
            +-- store.operationGraphForStage(stageId)
            +-- store.taskCount(stageId, attemptId)
            +-- store.taskList(stageId, attemptId, ...)
            |
            +-- makeTimeline()
            |     +-- タスクデータ取得（tasksFunc）
            |     +-- 時間配分計算
            |     +-- SVGバー生成
            |     +-- drawTaskAssignmentTimeline() [JavaScript]
            |
            +-- UIUtils.showDagVizForStage()
            +-- stagepage.js [モジュールロード]
                  +-- REST API経由でタスクテーブル動的描画
```

### データフロー図

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

HTTP GET /stages/stage/   ──▶  StagePage.render()          ──▶  HTML レスポンス
  ?id=X&attempt=Y                |
                                store.stageAttempt          ──▶  ステージサマリー
                                store.localitySummary       ──▶  ローカリティ分布
                                store.taskList              ──▶  タスクタイムライン
                                store.operationGraphForStage ──▶  DAG 可視化
                                stagepage.js (REST API)     ──▶  タスクテーブル(動的)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StagePage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala` | ソース | ステージ詳細ページの描画 |
| StagesTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagesTab.scala` | ソース | Stages タブの定義 |
| AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | ソース | データストアアクセス |
| AppStatusUtils.scala | `core/src/main/scala/org/apache/spark/status/AppStatusUtils.scala` | ソース | schedulerDelay, gettingResultTime 等の計算 |
| stagepage.js | `core/src/main/resources/org/apache/spark/ui/static/stagepage.js` | JavaScript | タスクテーブルの動的描画 |
| UIUtils.scala | `core/src/main/scala/org/apache/spark/ui/UIUtils.scala` | ソース | HTML ユーティリティ・DAG可視化 |
