この記事について
Delta Lake はレイクハウスアーキテクチャの核心技術である。オブジェクトストレージ上の Parquet ファイルに ACID トランザクション、スキーマ管理、バージョン管理を追加する。この記事では Delta Lake の内部構造を解説する。
1. Delta Lake とは
1-1. 基本構造
Delta Lake テーブルは、Parquet ファイル + トランザクションログ(_delta_log/)で構成される。
s3://datalake/sales/
├── _delta_log/ ← トランザクションログ
│ ├── 00000000000000000000.json ← Version 0
│ ├── 00000000000000000001.json ← Version 1
│ ├── 00000000000000000002.json ← Version 2
│ └── 00000000000000000010.checkpoint.parquet ← チェックポイント
├── part-00000-xxx.parquet ← データファイル
├── part-00001-xxx.parquet
└── part-00002-xxx.parquet
1-2. トランザクションログ
各 JSON ファイルが1つのトランザクション(バージョン)を表す。
// 00000000000000000001.json の例
{
"add": {
"path": "part-00003-xxx.parquet",
"size": 1048576,
"partitionValues": {"date": "2024-04-01"},
"stats": "{\"numRecords\":10000,\"minValues\":{\"amount\":1},\"maxValues\":{\"amount\":99999}}"
}
}ログに記録されるアクション:
| アクション | 説明 |
|---|---|
| add | ファイルの追加 |
| remove | ファイルの論理削除 |
| metaData | スキーマ変更 |
| txn | アプリケーショントランザクション ID |
| protocol | プロトコルバージョン |
| commitInfo | コミットのメタデータ(タイムスタンプ、操作種別) |
2. ACID トランザクション
2-1. 楽観的同時実行制御
Delta Lake は楽観的同時実行制御(Optimistic Concurrency Control)を採用。
Writer A: Version 2 を読み取り → 変換処理 → Version 3 として書き込み ✅
Writer B: Version 2 を読み取り → 変換処理 → Version 3 として書き込み ❌ 競合
→ Writer B は Version 3 を読み直して再試行
競合検出のルール: – 同じファイルを変更する場合 → 競合 – 異なるパーティションへの書き込み → 競合しない
2-2. 読み取りの一貫性
読み取りは特定のバージョンのスナップショットを参照する。書き込み中のデータは見えない(Snapshot Isolation)。
Reader: Version 5 のスナップショットを読み取り
Writer: Version 6 を書き込み中
→ Reader には Version 6 の変更は見えない
3. タイムトラベル
過去の任意のバージョンのデータを参照できる。
-- バージョン指定
SELECT * FROM sales VERSION AS OF 5;
-- タイムスタンプ指定
SELECT * FROM sales TIMESTAMP AS OF '2024-04-01 00:00:00';用途: – データの誤更新からの復旧 – 監査(過去の状態の確認) – ML モデルの再現性(学習時のデータを再取得)
4. スキーマエンフォースメントとエボリューション
4-1. スキーマエンフォースメント
テーブル定義と異なるスキーマのデータを書き込もうとするとエラーになる。
テーブル定義: [id: INT, name: STRING, amount: DECIMAL]
書き込みデータ: [id: INT, name: STRING, amount: DECIMAL, tax: DECIMAL]
→ エラー: tax カラムがテーブル定義にない
4-2. スキーマエボリューション
明示的にスキーマ変更を許可する。
-- カラム追加を許可して書き込み
ALTER TABLE sales ADD COLUMN tax DECIMAL(10,2);
-- または書き込み時に mergeSchema オプション対応する変更: – カラムの追加 – カラムの型の拡張(INT → LONG 等) – ネストされた構造の変更
5. データ最適化
5-1. OPTIMIZE(Compaction)
小さなファイルを結合して最適なサイズにする。
OPTIMIZE sales;
-- 小さなファイルを結合 → 読み取り性能向上5-2. Z-ORDER
指定カラムの値が近いデータを同じファイルにまとめる。複数カラムでのフィルタリングを高速化。
OPTIMIZE sales ZORDER BY (product_id, region);
-- product_id と region でフィルタするクエリが高速化5-3. VACUUM
タイムトラベルで不要になった古いファイルを物理削除する。
VACUUM sales RETAIN 168 HOURS; -- 7日より古いファイルを削除デフォルトの保持期間は7日。これより短くするとタイムトラベルができなくなる。
5-4. Liquid Clustering(新機能)
従来のパーティション + Z-ORDER を置き換える新しいデータ配置手法。
CREATE TABLE sales CLUSTER BY (date, region);
-- パーティションと Z-ORDER を統合的に管理メリット: – パーティションキーの事前設計が不要 – クラスタリングキーを後から変更可能 – OPTIMIZE 時に自動的に最適化
6. Delta Lake vs Iceberg vs Hudi
| 観点 | Delta Lake | Apache Iceberg | Apache Hudi |
|---|---|---|---|
| 開発元 | Databricks | Netflix → Apache | Uber → Apache |
| ACID | ✅ | ✅ | ✅ |
| タイムトラベル | ✅ | ✅ | ✅ |
| スキーマエボリューション | ✅ | ✅ | ✅ |
| パーティションエボリューション | △(Liquid Clustering) | ✅(Hidden Partitioning) | △ |
| エンジン依存 | Spark 中心(他も対応拡大中) | エンジン非依存 | Spark 中心 |
| Upsert / CDC | ✅ MERGE | ✅ MERGE | ✅(CDC に特化) |
| コミュニティ | Databricks 主導 | 幅広い(AWS, Apple 等) | Uber 主導 |
Databricks は Delta Lake を推進しつつ、UniForm 機能で Iceberg / Hudi との互換性も提供している。
7. まとめ
| 機能 | 説明 |
|---|---|
| トランザクションログ | JSON ファイルで全変更を記録。ACID の基盤 |
| ACID | 楽観的同時実行制御 + Snapshot Isolation |
| タイムトラベル | 過去の任意のバージョンを参照可能 |
| スキーマ管理 | エンフォースメント(拒否)+ エボリューション(許可) |
| OPTIMIZE | ファイル結合 + Z-ORDER でクエリ高速化 |
| VACUUM | 不要ファイルの物理削除 |
Delta Lake は「S3 上の Parquet ファイルに RDBMS の管理機能を追加する」技術。これがレイクハウスの核心。
参考文献
- Michael Armbrust et al. “Delta Lake: High-Performance ACID Table Storage over Cloud Object Stores.” VLDB, 2020.
- Databricks. “Delta Lake Documentation.” https://docs.delta.io/latest/
- Databricks. “Delta Lake Internals.” https://www.databricks.com/blog/2019/08/21/diving-into-delta-lake-unpacking-the-transaction-log.html