OTF Comparison
Apache Iceberg vs Apache Hudi vs Delta Lake: 包括的技術比較
本ドキュメントは、モダンデータレイクハウスにおける3大オープンテーブルフォーマット ── Apache Iceberg、Apache Hudi、Delta Lake ── の技術的特徴、アーキテクチャ、性能、エコシステムを網羅的に比較・分析するものである。
目次
- はじめに
- 各フォーマットの概要
- 歴史とガバナンス比較
- アーキテクチャ比較
- 機能比較(詳細)
- クエリエンジン互換性
- パフォーマンス比較
- メンテナンス操作比較
- 相互運用性
- エコシステムとツーリング
- コミュニティと採用状況
- マイグレーション戦略
- 選定フレームワーク
- 今後の収束トレンド
- まとめと推奨マトリクス
1. はじめに
1.1 なぜテーブルフォーマットが重要なのか
従来のデータレイクは、Hadoop Distributed File System (HDFS) やクラウドオブジェクトストレージ上に Parquet / ORC ファイルを単純に配置する方式が主流であった。しかし、この「ファイルの集合」アプローチには根本的な課題があった。
従来のデータレイクの課題:
| 課題カテゴリ | 具体的な問題 |
|---|---|
| トランザクション整合性 | 複数ファイルの書き込みが原子的でない。途中で失敗すると不整合データが残る |
| 同時実行制御 | 複数の書き込みプロセスが同時に動くとデータ破損のリスク |
| スキーマ管理 | スキーマ変更時に既存データとの整合性を保つのが困難 |
| レコード単位の更新 | 個別レコードの UPDATE/DELETE が非効率(パーティション全体の書き直し) |
| タイムトラベル | 過去の時点のデータスナップショットにアクセスできない |
| メタデータ管理 | ファイルリスティングに依存し、大規模データセットで性能劣化 |
| パーティション変更 | パーティションスキームの変更にデータ全体の再書き込みが必要 |
これらの課題を解決するために登場したのが、「オープンテーブルフォーマット (Open Table Format)」である。テーブルフォーマットは、物理的なファイル群の上に論理的なテーブル抽象層を設けることで、RDBMS に近いセマンティクスをデータレイクにもたらす。
1.2 レイクハウスパラダイム
レイクハウス (Lakehouse) は、データレイクの柔軟性・スケーラビリティ・低コストと、データウェアハウスのトランザクション整合性・スキーマ管理・ガバナンス機能を統合したアーキテクチャパラダイムである。
+------------------------------------------------------------------+
| レイクハウス アーキテクチャ |
+------------------------------------------------------------------+
| |
| +-----------+ +-----------+ +-----------+ +-----------+ |
| | BI | | ML/AI | | Streaming | | Data Eng | |
| | ツール | | ワークロード| | 処理 | | パイプライン| |
| +-----------+ +-----------+ +-----------+ +-----------+ |
| | | | | |
| +----------------------------------------------------------+ |
| | クエリエンジン層 | |
| | (Spark, Trino, Flink, Presto, Athena, etc.) | |
| +----------------------------------------------------------+ |
| | | | | |
| +----------------------------------------------------------+ |
| | オープンテーブルフォーマット層 | |
| | (Iceberg / Hudi / Delta Lake) | |
| | - ACID トランザクション | |
| | - スキーマ進化 | |
| | - タイムトラベル | |
| | - パーティション進化 | |
| | - 行レベル更新 | |
| +----------------------------------------------------------+ |
| | | | | |
| +----------------------------------------------------------+ |
| | ファイルフォーマット層 | |
| | (Apache Parquet / Apache ORC / Apache Avro) | |
| +----------------------------------------------------------+ |
| | | | | |
| +----------------------------------------------------------+ |
| | ストレージ層 | |
| | (S3 / ADLS / GCS / HDFS / MinIO) | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
レイクハウスの中核を担うのがオープンテーブルフォーマットであり、現在の主要なプレイヤーが Apache Iceberg、Apache Hudi、Delta Lake の3つである。本稿ではこれら3つを多角的に比較する。
1.3 本稿の対象読者と構成
本稿は以下の読者を対象としている:
- データプラットフォームのアーキテクトおよびエンジニア
- SRE / インフラストラクチャエンジニア
- テーブルフォーマットの選定を行う意思決定者
- データレイクからレイクハウスへの移行を検討している組織
各セクションでは、概念的な説明に加え、ASCII アーキテクチャ図、詳細な比較テーブル、具体的なコード例を提示し、実践的な理解を促す構成としている。
2. 各フォーマットの概要
2.1 Apache Iceberg
Apache Iceberg は、Netflix が開発し 2018 年にオープンソース化したオープンテーブルフォーマットである。2020 年に Apache Software Foundation (ASF) のトップレベルプロジェクトに昇格した。
設計思想: 「テーブルはファイルの集合ではなく、スナップショットの系列である」
Iceberg の最大の特徴は、ストレージ層からの完全な抽象化と、エンジン非依存の設計にある。テーブルの状態はスナップショットとして管理され、各スナップショットはマニフェストリストとマニフェストファイルの階層構造を通じてデータファイルを参照する。
主要な技術的特徴:
- Hidden Partitioning(隠しパーティショニング): ユーザーはパーティションカラムを意識する必要がなく、テーブル定義にパーティション変換関数を指定するだけでよい
- Partition Evolution(パーティション進化): データの再書き込みなしにパーティションスキームを変更できる
- Schema Evolution(スキーマ進化): カラム ID ベースの追跡により、カラムの追加・削除・名前変更・型変更を安全に行える
- Snapshot Isolation: 読み取りと書き込みが互いに干渉しない完全なスナップショット分離
- Multi-engine Support: Spark, Trino, Flink, Hive, Presto 等の主要エンジンすべてで利用可能
-- Iceberg テーブルの作成例
CREATE TABLE catalog.db.events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
payload STRING
) USING iceberg
PARTITIONED BY (days(event_time), bucket(16, user_id))
TBLPROPERTIES (
'write.format.default' = 'parquet',
'write.parquet.compression-codec' = 'zstd'
);
2.2 Apache Hudi
Apache Hudi (Hadoop Upserts Deletes and Incrementals) は、Uber が開発し 2019 年に Apache Software Foundation のトップレベルプロジェクトとなったテーブルフォーマットである。
設計思想: 「ストリーミングとバッチの統合、高頻度なインクリメンタル処理の実現」
Hudi は元々、Uber の大規模なライドシェアデータの効率的な upsert 処理のために設計された。そのため、CDC(Change Data Capture)やインクリメンタル処理に特に強みを持つ。
主要な技術的特徴:
- テーブルタイプの選択: Copy-on-Write (CoW) と Merge-on-Read (MoR) の2つのテーブルタイプを明示的にサポート
- Timeline ベースのメタデータ: テーブルの状態変更をタイムライン上のインスタントとして記録
- Incremental Query: 特定の時点以降の変更分のみを効率的に取得可能
- Built-in Indexing: ブルームフィルタ、HBase インデックス、バケットインデックス等の組み込みインデックス機能
- Record-level Metadata: レコードレベルでのメタデータ管理により、高効率な upsert を実現
-- Hudi テーブルの作成例
CREATE TABLE catalog.db.events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
payload STRING,
_hoodie_commit_time STRING,
_hoodie_commit_seqno STRING,
_hoodie_record_key STRING,
_hoodie_partition_path STRING,
_hoodie_file_name STRING
) USING hudi
TBLPROPERTIES (
'type' = 'mor',
'primaryKey' = 'event_id',
'preCombineField' = 'event_time',
'hoodie.table.name' = 'events',
'hoodie.datasource.write.recordkey.field' = 'event_id',
'hoodie.datasource.write.partitionpath.field' = 'event_time',
'hoodie.datasource.write.precombine.field' = 'event_time'
);
2.3 Delta Lake
Delta Lake は、Databricks が開発し 2019 年にオープンソース化したテーブルフォーマットである。2024 年に Linux Foundation に寄贈された。
設計思想: 「Spark エコシステムとの深い統合、シンプルさと信頼性の両立」
Delta Lake は Apache Spark との緊密な統合を最大の強みとし、Databricks プラットフォームの中核コンポーネントとして位置づけられている。
主要な技術的特徴:
- JSON ベースのトランザクションログ:
_delta_logディレクトリにトランザクション操作を JSON 形式で記録 - Optimistic Concurrency Control: 楽観的同時実行制御によるマルチライター対応
- Z-Order Clustering / Liquid Clustering: データの物理的なレイアウトを最適化
- Change Data Feed (CDF): テーブルの変更を行レベルで追跡・配信
- Delta Sharing: オープンプロトコルによるセキュアなデータ共有
-- Delta Lake テーブルの作成例
CREATE TABLE catalog.db.events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
payload STRING
) USING delta
PARTITIONED BY (date_trunc('day', event_time))
TBLPROPERTIES (
'delta.enableChangeDataFeed' = 'true',
'delta.logRetentionDuration' = 'interval 30 days',
'delta.deletedFileRetentionDuration' = 'interval 7 days'
);
2.4 三者のポジショニング概要
エンジン非依存性
^
|
Iceberg |
* |
|
|
Hudi | Delta Lake
* | *
|
CDC/Upsert <---------+---------> Spark 統合
特化 | 特化
|
|
v
ベンダー統合性
| 特性 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 主な強み | マルチエンジン対応、パーティション進化 | 高頻度 upsert、CDC、インクリメンタル処理 | Spark/Databricks 統合、Liquid Clustering |
| 設計の重点 | オープン標準、エンジン非依存 | ストリーミング・バッチ統合 | パフォーマンスと使いやすさ |
| 典型的ユースケース | マルチエンジン分析基盤 | リアルタイムデータパイプライン | Databricks 中心の分析基盤 |
3. 歴史とガバナンス比較
3.1 起源と発展
Apache Iceberg の歴史
| 年 | イベント |
|---|---|
| 2017 | Netflix にて Ryan Blue らが開発を開始。社内では「Netflix Table Format」と呼ばれていた |
| 2018 | Apache Software Foundation に寄贈、Apache Incubator プロジェクトとして公開 |
| 2020 | ASF トップレベルプロジェクトに昇格 |
| 2021 | Tabular 社設立(Iceberg 創設者による商用サポート企業) |
| 2022 | Iceberg v1 仕様の安定化。主要クラウドベンダーのサポート拡大 |
| 2023 | Snowflake が Tabular 社を買収。Iceberg が事実上の業界標準に近づく |
| 2024 | Apache Iceberg v2 仕様が広く普及。Row-level deletes の V2 フォーマット対応 |
| 2025 | REST Catalog 仕様の標準化。Polaris Catalog の登場 |
Apache Hudi の歴史
| 年 | イベント |
|---|---|
| 2016 | Uber にて Vinoth Chandar らが開発を開始。社内のインクリメンタルデータ処理基盤として |
| 2017 | 「Hoodie」として社内で本格運用開始 |
| 2019 | Apache Software Foundation に寄贈、ASF トップレベルプロジェクトに昇格 |
| 2020 | Hudi 0.6 リリース。MoR テーブルの安定化 |
| 2021 | Hudi 0.9 リリース。Flink 統合の強化 |
| 2022 | Hudi 0.12 リリース。メタデータテーブル機能の追加 |
| 2023 | Hudi 0.14 リリース。Record-level index の導入 |
| 2024 | Hudi 1.0 リリース。大規模なアーキテクチャ刷新 |
| 2025 | Hudi 1.x 系列の安定化。Lake Cache などの新機能 |
Delta Lake の歴史
| 年 | イベント |
|---|---|
| 2017 | Databricks 社内で開発開始 |
| 2019 | Delta Lake 0.1 をオープンソースとして公開 |
| 2020 | Delta Lake 0.7 リリース。SQL サポートの強化 |
| 2021 | Delta Lake 1.0 リリース。安定版 API の確立 |
| 2022 | Delta Lake 2.0 リリース。Change Data Feed の GA |
| 2023 | Delta Lake 3.0 リリース。UniForm(Iceberg 互換読み取り)機能追加 |
| 2024 | Linux Foundation に寄贈。Delta Lake 4.0 リリース。Liquid Clustering の GA |
| 2025 | Delta Kernel の安定化。マルチエンジンサポートの拡大 |
3.2 ガバナンス構造比較
| ガバナンス項目 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 管理団体 | Apache Software Foundation | Apache Software Foundation | Linux Foundation |
| ライセンス | Apache 2.0 | Apache 2.0 | Apache 2.0 |
| 仕様とコードの分離 | あり(仕様書が独立して存在) | なし(コードが仕様) | あり(Delta Protocol) |
| 主要な支援企業 | Apple, Netflix, Snowflake, AWS, Dremio, Tabular | Uber, AWS, ByteDance, Onehouse | Databricks, Microsoft |
| コントリビューター数 | 800+ | 500+ | 300+ |
| OSS/商用の分離 | 完全 OSS | 完全 OSS | OSS 版と Databricks 版で機能差あり |
| 意思決定プロセス | ASF コンセンサスベース | ASF コンセンサスベース | LF ガバナンス |
3.3 コミュニティの活発さ(2025年時点の概算)
| メトリクス | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| GitHub Stars | ~7,000 | ~5,500 | ~7,500 |
| GitHub Contributors | 800+ | 500+ | 300+ |
| Monthly Commits | 200+ | 150+ | 80+ |
| Slack/Discord メンバー | 5,000+ | 3,000+ | 4,000+ |
| 関連企業数 | 50+ | 30+ | 20+ |
重要な考察: Iceberg は ASF の完全なオープンガバナンスモデルにより、特定のベンダーに依存しない中立的な立場を維持している。Delta Lake は長らく Databricks 主導であったが、Linux Foundation への寄贈により中立性が向上した。Hudi は ASF のガバナンス下にあるが、コアコントリビューターの多様性では Iceberg に及ばない部分もある。
4. アーキテクチャ比較
4.1 全体アーキテクチャの概念図
Apache Iceberg のアーキテクチャ
+------------------------------------------------------------------+
| Apache Iceberg アーキテクチャ |
+------------------------------------------------------------------+
| |
| +--------------------+ |
| | Catalog | カタログがテーブルの「現在の状態」を指す |
| | (Hive/Glue/ | ポインタを保持 |
| | Nessie/REST) | |
| +--------+-----------+ |
| | |
| v |
| +--------------------+ |
| | Metadata File | テーブルメタデータ (JSON/Avro) |
| | (metadata.json) | - テーブルスキーマ |
| | | - パーティション仕様 |
| | | - スナップショット一覧 |
| | | - ソート順 |
| +--------+-----------+ |
| | |
| v |
| +--------------------+ |
| | Snapshot | テーブルの特定時点の状態 |
| | (snapshot-xxx) | - マニフェストリストへの参照 |
| | | - 操作タイプ (append/overwrite/delete) |
| +--------+-----------+ |
| | |
| v |
| +--------------------+ |
| | Manifest List | マニフェストファイルの一覧 |
| | (snap-xxx.avro) | - 各マニフェストのパーティション統計情報 |
| | | - ファイル数・サイズの集計 |
| +--------+-----------+ |
| | |
| v |
| +--------------------+ +--------------------+ |
| | Manifest File | | Manifest File | |
| | (manifest-xxx.avro)| | (manifest-yyy.avro)| |
| | - data file 一覧 | | - data file 一覧 | |
| | - カラム統計情報 | | - カラム統計情報 | |
| | - パーティション値 | | - パーティション値 | |
| +--------+-----------+ +--------+-----------+ |
| | | |
| v v |
| +----------------+ +----------------+ +----------------+ |
| | Data File | | Data File | | Data File | |
| | (Parquet/ORC) | | (Parquet/ORC) | | (Parquet/ORC) | |
| +----------------+ +----------------+ +----------------+ |
| |
| +----------------+ (Optional) |
| | Delete File | Position Delete / Equality Delete |
| | (Parquet) | V2 フォーマットで行レベル削除をサポート |
| +----------------+ |
| |
+------------------------------------------------------------------+
Iceberg のメタデータ階層の特徴:
- 3段階の階層構造: Metadata File -> Manifest List -> Manifest File -> Data File という階層により、大規模テーブルでも効率的なファイル探索が可能
- 統計情報の伝播: 各レベルで統計情報(min/max 値、null count 等)を保持し、クエリプランニング時の枝刈りに活用
- 不変性: すべてのメタデータファイルは不変(immutable)。新しい状態は新しいファイルとして書き込まれる
- スナップショット分離: 読み取りは特定のスナップショットに固定されるため、書き込み中の影響を受けない
Apache Hudi のアーキテクチャ
+------------------------------------------------------------------+
| Apache Hudi アーキテクチャ |
+------------------------------------------------------------------+
| |
| +--------------------+ |
| | Timeline | テーブルの全操作履歴 |
| | (.hoodie/) | - Instant (タイムスタンプ + アクション) |
| | | - REQUESTED -> INFLIGHT -> COMPLETED |
| +--------+-----------+ |
| | |
| v |
| +------------------------------------------------------------+ |
| | Table Metadata (Metadata Table) | |
| | - ファイル一覧 (files partition) | |
| | - カラム統計 (column_stats partition) | |
| | - ブルームフィルタ (bloom_filters partition) | |
| | - Record Index (record_index partition) | |
| +------------------------------------------------------------+ |
| | |
| v |
| +------------------------------+ |
| | | |
| v v |
| Copy-on-Write (CoW) Merge-on-Read (MoR) |
| |
| +----------------+ +----------------+ |
| | File Group | | File Group | |
| | +------------+ | | +------------+ | |
| | | Base File | | | | Base File | | |
| | | (Parquet) | | | | (Parquet) | | |
| | +------------+ | | +------------+ | |
| +----------------+ | +------------+ | |
| | | Log File 1 | | |
| 書き込み時に新しい | | (Avro) | | |
| Parquet ファイルを | +------------+ | |
| 完全に書き直す | +------------+ | |
| | | Log File 2 | | |
| | | (Avro) | | |
| | +------------+ | |
| +----------------+ |
| |
| 読み取り時にベースファイルと |
| ログファイルをマージ |
| |
+------------------------------------------------------------------+
Hudi のタイムライン アーキテクチャの特徴:
- Timeline ベースの管理:
.hoodieディレクトリ内に全操作がタイムスタンプ順に記録される - 3段階のステート: REQUESTED -> INFLIGHT -> COMPLETED のライフサイクルで各操作を管理
- File Group 概念: データファイルは File Group に属し、各 File Group は一意の File ID を持つ
- Record Key: 各レコードにユニークキーが必須。これにより効率的な upsert が可能
- Metadata Table: Hudi 独自のメタデータテーブルにより、ファイルリスティングを回避
Delta Lake のアーキテクチャ
+------------------------------------------------------------------+
| Delta Lake アーキテクチャ |
+------------------------------------------------------------------+
| |
| +--------------------+ |
| | Transaction Log | _delta_log/ ディレクトリ |
| | (_delta_log/) | |
| | | |
| | +----------------+ | |
| | | 000000.json | | 各 JSON ファイルが1つのコミットを表す |
| | | 000001.json | | - AddFile / RemoveFile アクション |
| | | 000002.json | | - メタデータ変更 |
| | | ... | | - プロトコル変更 |
| | +----------------+ | |
| | | |
| | +----------------+ | |
| | | 000010. | | 10コミットごとのチェックポイント |
| | | checkpoint. | | (Parquet 形式) |
| | | parquet | | 読み取り高速化のための状態スナップショット |
| | +----------------+ | |
| | | |
| | +----------------+ | |
| | | _last_ | | 最新チェックポイントへのポインタ |
| | | checkpoint | | |
| | +----------------+ | |
| +--------+-----------+ |
| | |
| v |
| +----------------+ +----------------+ +----------------+ |
| | Data File | | Data File | | Data File | |
| | (Parquet) | | (Parquet) | | (Parquet) | |
| +----------------+ +----------------+ +----------------+ |
| |
| +----------------+ (Optional, with DV enabled) |
| | Deletion | 行レベル削除を追跡するビットマップ |
| | Vector File | Parquet ファイルに紐づく |
| | (.bin) | |
| +----------------+ |
| |
+------------------------------------------------------------------+
Delta Lake のトランザクションログの特徴:
- JSON ベースのログ: 各コミットは独立した JSON ファイル。シンプルで理解しやすい
- チェックポイント: 10コミットごとに Parquet 形式のチェックポイントを作成し、読み取り時のログ再生を高速化
- _last_checkpoint: 最新のチェックポイントファイルを指すポインタ
- Deletion Vectors: V2 以降で導入された行レベル削除の仕組み。ファイル全体の書き直しを回避
- Flat Structure: Iceberg と異なり、メタデータは階層構造ではなくフラットなログ形式
4.2 メタデータ管理の比較
| メタデータ項目 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| メタデータ形式 | Avro + JSON | Avro + Timeline ファイル | JSON + Parquet チェックポイント |
| メタデータの構造 | 階層構造(3段階) | タイムライン + メタデータテーブル | フラットログ + チェックポイント |
| ファイル一覧管理 | マニフェストファイル | メタデータテーブル / ファイルリスティング | トランザクションログ / チェックポイント |
| カラム統計 | マニフェストファイルに格納 | メタデータテーブルに格納 | トランザクションログに格納 |
| パーティション統計 | マニフェストリストに格納 | メタデータテーブルに格納 | トランザクションログに格納 |
| メタデータサイズ | 中(階層化により分散) | 大(メタデータテーブルが別途必要) | 小〜中(チェックポイントで圧縮) |
| スケーラビリティ | 優れる(階層的枝刈り) | 良い(メタデータテーブル) | 中程度(チェックポイントが肥大化しうる) |
4.3 ファイル組織の比較
Iceberg のファイルレイアウト:
tablename/
metadata/
v1.metadata.json
v2.metadata.json <- 現在のメタデータ
snap-001.avro <- マニフェストリスト
snap-002.avro
manifest-aaa.avro <- マニフェストファイル
manifest-bbb.avro
data/
event_time_day=2025-01-01/
user_id_bucket=0/
file-001.parquet
file-002.parquet
user_id_bucket=1/
file-003.parquet
Hudi のファイルレイアウト:
tablename/
.hoodie/
hoodie.properties <- テーブル設定
20250101120000.commit <- コミットメタデータ
20250101130000.deltacommit <- デルタコミット(MoR)
20250101140000.clean <- クリーニング操作
.hoodie/metadata/ <- メタデータテーブル
files/
column_stats/
bloom_filters/
2025/01/01/ <- パーティション
filegroup-001_base.parquet
.filegroup-001_log.1.avro <- ログファイル(MoR)
filegroup-002_base.parquet
Delta Lake のファイルレイアウト:
tablename/
_delta_log/
00000000000000000000.json
00000000000000000001.json
00000000000000000002.json
00000000000000000010.checkpoint.parquet
_last_checkpoint
event_time=2025-01-01/
part-00000-xxx.parquet
part-00001-xxx.parquet
part-00000-xxx.deletion_vector.bin <- Deletion Vector
4.4 カタログ統合
| カタログ | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| Hive Metastore | ネイティブ対応 | ネイティブ対応 | ネイティブ対応 |
| AWS Glue | ネイティブ対応 | ネイティブ対応 | ネイティブ対応 |
| Nessie | ネイティブ対応(Git-like) | 非対応 | 非対応 |
| REST Catalog | ネイティブ対応(標準仕様あり) | 非対応 | 非対応 |
| Polaris Catalog | ネイティブ対応 | 非対応 | 非対応 |
| Unity Catalog | 対応 | 対応 | ネイティブ対応 |
| Hadoop Catalog | ネイティブ対応 | - | - |
| JDBC Catalog | ネイティブ対応 | - | - |
考察: カタログ統合は Iceberg が最も充実している。特に REST Catalog 仕様の標準化により、カタログの実装を自由に選択できる柔軟性がある。Nessie による Git-like なブランチング・タギングも Iceberg 固有の強みである。Delta Lake は Unity Catalog との統合に注力しているが、Unity Catalog 自体がオープンソース化されたことでアクセシビリティは改善している。
5. 機能比較(詳細)
5.1 機能比較サマリーテーブル
| 機能 | Apache Iceberg | Apache Hudi | Delta Lake |
|---|---|---|---|
| ACID トランザクション | Serializable Snapshot Isolation | Multi-version Concurrency Control | Serializable (OCC) |
| タイムトラベル | スナップショットベース | タイムラインベース | バージョンベース |
| スキーマ進化 | 完全対応(ID ベース) | 完全対応 | 完全対応 |
| パーティション進化 | ネイティブ対応 | 限定的 | 非対応(Liquid Clustering で代替) |
| 隠しパーティショニング | ネイティブ対応 | 非対応 | 非対応 |
| 行レベル更新 | Position/Equality Delete | CoW + MoR | Deletion Vectors |
| Copy-on-Write | 対応 | ネイティブ対応 | デフォルト動作 |
| Merge-on-Read | 対応(Delete Files) | ネイティブ対応 | Deletion Vectors で対応 |
| 同時実行制御 | Optimistic Concurrency | Optimistic Concurrency + Lock | Optimistic Concurrency |
| ブランチング | ネイティブ対応 | 非対応 | 非対応(Nessie 連携で可能) |
| タギング | ネイティブ対応 | Savepoint | 非対応 |
| ストリーミング対応 | Spark/Flink Streaming | Spark/Flink Streaming | Spark Structured Streaming |
| CDC/CDF | Incremental Scan | Incremental Query (ネイティブ) | Change Data Feed |
| Z-Order | 対応(Spark 連携) | 対応(Clustering) | ネイティブ対応 |
| Liquid Clustering | 非対応 | 非対応 | ネイティブ対応 |
| Row-level Index | 非対応 | Record Index | 非対応 |
| ファイルフォーマット | Parquet, ORC, Avro | Parquet, ORC, HFile | Parquet のみ |
| 圧縮コーデック | 全般対応 | 全般対応 | 全般対応 |
5.2 ACID トランザクション
Iceberg の ACID 実装
Iceberg は Serializable Snapshot Isolation を採用している。各書き込み操作は新しいスナップショットを生成し、カタログのアトミックな更新(compare-and-swap)により一貫性を保証する。
書き込みフロー:
1. 現在のスナップショット S1 を読み取り
2. 新しいデータファイルを書き込み
3. 新しいマニフェストファイルを作成
4. 新しいマニフェストリストを作成
5. 新しいスナップショット S2 を作成
6. カタログの CAS 操作で S1 -> S2 に更新
- 成功: コミット完了
- 失敗(他のライターが先にコミット): リトライ
# Iceberg のトランザクション例 (PySpark)
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.config("spark.sql.catalog.local", "org.apache.iceberg.spark.SparkCatalog") \
.config("spark.sql.catalog.local.type", "hadoop") \
.config("spark.sql.catalog.local.warehouse", "s3://bucket/warehouse") \
.getOrCreate()
# ACID INSERT
spark.sql("""
INSERT INTO local.db.events
SELECT * FROM staging_events
WHERE event_date = '2025-01-01'
""")
# ACID MERGE (Upsert)
spark.sql("""
MERGE INTO local.db.events t
USING updates s
ON t.event_id = s.event_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
Hudi の ACID 実装
Hudi は Multi-version Concurrency Control (MVCC) をベースとし、Timeline ベースのコミットプロトコルを使用する。
書き込みフロー:
1. タイムライン上に新しい Instant を REQUESTED として作成
2. Instant を INFLIGHT に遷移
3. データファイルの書き込み(CoW: 新 Parquet / MoR: ログファイル)
4. Instant を COMPLETED に遷移(アトミック)
5. 古い Instant のクリーンアップをスケジュール
# Hudi のトランザクション例 (PySpark)
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer") \
.config("spark.sql.catalog.spark_catalog",
"org.apache.spark.sql.hudi.catalog.HoodieCatalog") \
.getOrCreate()
# ACID UPSERT
hudi_options = {
'hoodie.table.name': 'events',
'hoodie.datasource.write.recordkey.field': 'event_id',
'hoodie.datasource.write.precombine.field': 'event_time',
'hoodie.datasource.write.operation': 'upsert',
'hoodie.datasource.write.table.type': 'MERGE_ON_READ',
}
df.write.format("hudi") \
.options(**hudi_options) \
.mode("append") \
.save("s3://bucket/warehouse/events")
# SQL による MERGE
spark.sql("""
MERGE INTO hudi_catalog.db.events t
USING updates s
ON t.event_id = s.event_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
Delta Lake の ACID 実装
Delta Lake は Serializable Isolation と Optimistic Concurrency Control (OCC) を採用する。
書き込みフロー:
1. 現在のテーブルバージョン V を読み取り
2. 新しいデータファイルを書き込み
3. 新しいコミット JSON (V+1) をトランザクションログに書き込み
- ストレージの原子的 put (S3 put-if-absent 等) を利用
4. コンフリクト検出
- 成功: コミット完了
- 失敗: コンフリクト解消してリトライ
# Delta Lake のトランザクション例 (PySpark)
from pyspark.sql import SparkSession
from delta.tables import DeltaTable
spark = SparkSession.builder \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog",
"org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()
# ACID MERGE (Upsert)
delta_table = DeltaTable.forPath(spark, "s3://bucket/warehouse/events")
delta_table.alias("t") \
.merge(updates_df.alias("s"), "t.event_id = s.event_id") \
.whenMatchedUpdateAll() \
.whenNotMatchedInsertAll() \
.execute()
# SQL による MERGE
spark.sql("""
MERGE INTO delta.`s3://bucket/warehouse/events` t
USING updates s
ON t.event_id = s.event_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
5.3 タイムトラベル
| タイムトラベル機能 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| スナップショット ID による | 対応 | 対応(Instant 時刻) | 対応(バージョン番号) |
| タイムスタンプによる | 対応 | 対応 | 対応 |
| as-of クエリ構文 | FOR SYSTEM_TIME AS OF | timestamp as of | VERSION AS OF / TIMESTAMP AS OF |
| 保持期間設定 | history.expire.max-snapshot-age-ms | hoodie.cleaner.commits.retained | delta.logRetentionDuration |
| デフォルト保持期間 | 5日 | 10コミット | 30日 |
| ロールバック | CALL rollback_to_snapshot | CALL rollback_to_instant | RESTORE TABLE ... TO VERSION |
-- Iceberg タイムトラベル
SELECT * FROM catalog.db.events
FOR SYSTEM_TIME AS OF '2025-01-01 00:00:00';
SELECT * FROM catalog.db.events
FOR SYSTEM_VERSION AS OF 1234567890; -- snapshot ID
-- Iceberg ロールバック
CALL catalog.system.rollback_to_snapshot('db.events', 1234567890);
-- Hudi タイムトラベル
SELECT * FROM hudi_catalog.db.events
TIMESTAMP AS OF '2025-01-01 00:00:00';
-- Hudi ロールバック
CALL rollback_to_instant(table => 'db.events',
instant_time => '20250101120000');
-- Delta Lake タイムトラベル
SELECT * FROM delta.`s3://bucket/events`
VERSION AS OF 10;
SELECT * FROM delta.`s3://bucket/events`
TIMESTAMP AS OF '2025-01-01 00:00:00';
-- Delta Lake ロールバック
RESTORE TABLE delta.`s3://bucket/events` TO VERSION AS OF 10;
5.4 スキーマ進化
| スキーマ進化機能 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| カラム追加 | 対応 | 対応 | 対応 |
| カラム削除 | 対応 | 対応 | 対応 |
| カラム名変更 | 対応(ID ベース) | 対応 | 対応 |
| カラム型変更(互換) | 対応(拡大変換) | 対応(拡大変換) | 対応(拡大変換) |
| カラム順序変更 | 対応 | 対応 | 対応 |
| ネスト型の進化 | 完全対応 | 部分対応 | 部分対応 |
| 追跡方式 | カラム ID(整数) | カラム名 | カラム名 |
Iceberg のスキーマ進化の優位性:
Iceberg は各カラムに一意の整数 ID を割り当て、この ID を通じてカラムを追跡する。これにより、カラムの名前変更や順序変更が既存データに影響を与えない。
-- Iceberg のスキーマ進化例
ALTER TABLE catalog.db.events ADD COLUMN region STRING;
ALTER TABLE catalog.db.events RENAME COLUMN payload TO event_payload;
ALTER TABLE catalog.db.events ALTER COLUMN user_id TYPE BIGINT; -- INT -> BIGINT
ALTER TABLE catalog.db.events DROP COLUMN old_column;
-- ネスト型の進化
ALTER TABLE catalog.db.events
ADD COLUMN metadata STRUCT<source STRING, version INT>;
ALTER TABLE catalog.db.events
ADD COLUMN metadata.tags ARRAY<STRING>;
5.5 パーティション進化
パーティション進化は Iceberg の最も差別化された機能の一つ である。
| パーティション進化 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| パーティション変更 | データ再書き込み不要 | データ再書き込み必要 | パーティション変更不可 |
| パーティション変換関数 | years, months, days, hours, bucket, truncate | 限定的 | 非対応 |
| 隠しパーティショニング | 対応 | 非対応 | 非対応 |
| 新旧パーティションの共存 | 対応 | 非対応 | 非対応 |
-- Iceberg のパーティション進化例
-- 初期: 日単位パーティション
CREATE TABLE catalog.db.events (
event_id BIGINT,
event_time TIMESTAMP,
data STRING
) USING iceberg
PARTITIONED BY (days(event_time));
-- データが増加 → 時間単位に変更(既存データは再書き込み不要)
ALTER TABLE catalog.db.events
ADD PARTITION FIELD hours(event_time);
ALTER TABLE catalog.db.events
DROP PARTITION FIELD days(event_time);
-- 結果: 新しいデータは時間単位、古いデータは日単位のパーティションに保持される
-- クエリエンジンは両方のパーティションスキームを透過的に処理する
-- ユーザー側の SELECT 文は変わらない:
SELECT * FROM catalog.db.events
WHERE event_time BETWEEN '2025-01-01' AND '2025-01-02';
-- Iceberg が自動的に適切なパーティションを選択する
Delta Lake の代替: Liquid Clustering
Delta Lake はパーティション進化をサポートしないが、代わりに Liquid Clustering を提供している。
-- Delta Lake の Liquid Clustering
CREATE TABLE delta_events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
data STRING
) USING delta
CLUSTER BY (event_time, user_id); -- パーティションではなくクラスタリング
-- クラスタリングキーの変更(データの再書き込みは徐々に行われる)
ALTER TABLE delta_events CLUSTER BY (user_id, event_type);
-- OPTIMIZE で実際にデータを再配置
OPTIMIZE delta_events;
5.6 行レベル更新 (CoW vs MoR)
各フォーマットにおける行レベル更新(UPDATE / DELETE / MERGE)の実装を詳細に比較する。
+------------------------------------------------------------------+
| 行レベル更新のアプローチ比較 |
+------------------------------------------------------------------+
| |
| Iceberg: |
| |
| [Data File A] + [Position Delete File] = 読み取り時に |
| row1: alice pos: file-A, row 2 row2 を除外 |
| row2: bob pos: file-A, row 4 row4 を除外 |
| row3: carol |
| row4: dave + [Equality Delete File] = 条件一致レコードを |
| user_id = 'bob' 除外 |
| |
| Hudi (MoR): |
| |
| [Base File] + [Log File 1] + [Log File 2] = Compaction で |
| row1: alice UPDATE bob→bobby DELETE carol マージ |
| row2: bob |
| row3: carol |
| row4: dave |
| |
| Hudi (CoW): |
| |
| [Old File] → [New File (書き直し)] |
| row1: alice row1: alice |
| row2: bob row2: bobby ← 更新されたレコード |
| row3: carol row4: dave ← carol は削除 |
| row4: dave |
| |
| Delta Lake (Deletion Vectors): |
| |
| [Data File] + [Deletion Vector (.bin)] = 読み取り時に |
| row1: alice bitmap: [0,1,0,0] row2 を除外 |
| row2: bob (1 = deleted) + 新しいファイルに |
| row3: carol 更新後の bob を格納 |
| row4: dave |
| |
+------------------------------------------------------------------+
| 行レベル更新 | Iceberg | Hudi (CoW) | Hudi (MoR) | Delta Lake |
|---|---|---|---|---|
| UPDATE メカニズム | Delete + Insert | ファイル書き直し | ログ追記 | DV + Insert |
| DELETE メカニズム | Delete File | ファイル書き直し | ログ追記 | Deletion Vector |
| 書き込みコスト | 中 | 高 | 低 | 低〜中 |
| 読み取りコスト | 低〜中 | 低 | 高 | 低〜中 |
| ストレージ効率 | 中 | 低 | 高 | 中〜高 |
| 書き込みレイテンシ | 中 | 高 | 低 | 低〜中 |
| 読み取りレイテンシ | 低 | 低 | 高(Compaction前) | 低 |
5.7 同時実行制御
| 同時実行制御 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 基本方式 | Optimistic (OCC) | Optimistic + Lock Provider | Optimistic (OCC) |
| コンフリクト解決 | Serializable 検証 | File-level 検証 | File-level 検証 |
| マルチライター | 対応(同一パーティション可) | 対応(Lock Provider 必要) | 対応(S3 は制限あり) |
| ライター間の分離 | Serializable | Snapshot | Serializable |
| Catalog Lock | カタログ依存 | Lock Provider 設定可能 | ストレージ依存 |
Iceberg の同時実行制御フロー:
Writer A: Writer B:
| |
| Read Snapshot S1 | Read Snapshot S1
| |
| Write data files | Write data files
| |
| Create new snapshot S2 |
| CAS: S1 -> S2 (成功) |
| | Create new snapshot S3
| | CAS: S1 -> S3 (失敗: S1 は既に S2)
| |
| | Retry: Read S2
| | Validate: S2 との競合チェック
| | - 同じファイルを変更していないか
| | - パーティションが重複していないか
| | 競合なし: Create S3 based on S2
| | CAS: S2 -> S3 (成功)
5.8 ブランチングとタギング
| ブランチ/タグ | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| テーブルレベルブランチ | ネイティブ対応 (v1.2+) | 非対応 | 非対応 |
| テーブルレベルタグ | ネイティブ対応 (v1.2+) | Savepoint | 非対応 |
| カタログレベルブランチ | Nessie 連携 | 非対応 | 非対応 |
| WAP (Write-Audit-Publish) | ネイティブ対応 | 非対応 | 非対応 |
-- Iceberg のブランチング例
-- ブランチの作成
ALTER TABLE catalog.db.events
CREATE BRANCH audit_branch;
-- ブランチへの書き込み
SET spark.wap.branch = audit_branch;
INSERT INTO catalog.db.events VALUES (1, current_timestamp(), 100, 'test', 'data');
-- ブランチのデータを検証
SELECT * FROM catalog.db.events VERSION AS OF 'audit_branch';
-- 検証後にメインにマージ(Fast-forward)
CALL catalog.system.fast_forward('db.events', 'main', 'audit_branch');
-- タグの作成(特定スナップショットにラベルを付与)
ALTER TABLE catalog.db.events
CREATE TAG `release-2025-01` AS OF VERSION 1234567890;
-- タグによるクエリ
SELECT * FROM catalog.db.events VERSION AS OF 'release-2025-01';
5.9 ストリーミングサポート
| ストリーミング機能 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| Spark Structured Streaming | Source + Sink | Source + Sink | Source + Sink(最も成熟) |
| Flink Streaming | Source + Sink | Source + Sink(最も成熟) | 限定的 |
| Kafka Connect | コミュニティ対応 | ネイティブ対応 | コミュニティ対応 |
| マイクロバッチ | 対応 | 対応 | 対応 |
| Continuous Processing | 対応 | 対応 | 対応 |
| Exactly-once | 対応 | 対応 | 対応 |
# Iceberg Spark Streaming Sink
streaming_df.writeStream \
.format("iceberg") \
.outputMode("append") \
.option("checkpointLocation", "s3://bucket/checkpoints/events") \
.toTable("catalog.db.events")
# Hudi Flink Streaming Sink (SQL)
# Flink SQL:
# CREATE TABLE hudi_events (
# event_id BIGINT,
# event_time TIMESTAMP(3),
# user_id BIGINT,
# event_type STRING
# ) WITH (
# 'connector' = 'hudi',
# 'path' = 's3://bucket/warehouse/events',
# 'table.type' = 'MERGE_ON_READ',
# 'hoodie.datasource.write.recordkey.field' = 'event_id',
# 'write.precombine.field' = 'event_time'
# );
# Delta Lake Spark Streaming
streaming_df.writeStream \
.format("delta") \
.outputMode("append") \
.option("checkpointLocation", "s3://bucket/checkpoints/events") \
.start("s3://bucket/warehouse/events")
5.10 Change Data Capture / Change Data Feed
| CDC/CDF | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 機能名 | Incremental Scan / CDC | Incremental Query | Change Data Feed (CDF) |
| 変更タイプの追跡 | insert, delete, update | insert, update, delete | insert, update_preimage, update_postimage, delete |
| 有効化方法 | デフォルトで利用可能 | デフォルトで利用可能 | delta.enableChangeDataFeed = true で有効化 |
| 変更データの取得 | Snapshot diff API | Incremental Query | table_changes() 関数 |
| ストリーミング CDC | 対応 | 対応(最も成熟) | 対応 |
-- Iceberg Incremental Scan
-- スナップショット間の変更を取得
SELECT * FROM catalog.db.events
FOR SYSTEM_TIME AS OF '2025-01-02'
MINUS
SELECT * FROM catalog.db.events
FOR SYSTEM_TIME AS OF '2025-01-01';
-- Hudi Incremental Query
-- 特定時点以降の変更を取得
SELECT * FROM hudi_catalog.db.events
WHERE _hoodie_commit_time > '20250101120000';
-- Hudi の CDC モード(Spark DataFrame API)
-- spark.read.format("hudi")
-- .option("hoodie.datasource.query.type", "incremental")
-- .option("hoodie.datasource.read.begin.instanttime", "20250101120000")
-- .load("s3://bucket/warehouse/events")
-- Delta Lake Change Data Feed
SELECT * FROM table_changes('events', 2, 5);
-- バージョン 2 から 5 の間の変更を取得
SELECT * FROM table_changes('events', '2025-01-01', '2025-01-02');
-- タイムスタンプベース
6. クエリエンジン互換性
6.1 クエリエンジン互換性マトリクス
| クエリエンジン | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| Apache Spark | 完全対応(読み書き) | 完全対応(読み書き) | 完全対応(読み書き)※ 最も成熟 |
| Trino (旧 PrestoSQL) | 完全対応(読み書き) | 読み取り対応、書き込み限定的 | 読み取り対応、書き込み限定的 |
| Apache Flink | 対応(読み書き) | 完全対応(読み書き)※ 最も成熟 | 限定的(読み取り主体) |
| Apache Hive | 対応(読み書き) | 対応(読み書き) | 対応(読み取り主体) |
| Presto | 対応(読み書き) | 対応(読み取り) | 対応(読み取り) |
| AWS Athena | ネイティブ対応(v3+) | ネイティブ対応 | ネイティブ対応 |
| Google BigQuery | ネイティブ対応 | 限定的 | 対応(BigLake 経由) |
| Snowflake | ネイティブ対応(Iceberg Tables) | 非対応 | 非対応 |
| Databricks | 対応(UniForm 経由含む) | 対応 | ネイティブ対応(最適化済み) |
| Dremio | ネイティブ対応(最適化済み) | 非対応 | 対応(読み取り) |
| StarRocks | 対応(読み取り) | 対応(読み取り) | 対応(読み取り) |
| Apache Doris | 対応(読み取り) | 対応(読み取り) | 対応(読み取り) |
| ClickHouse | 対応(読み取り) | 限定的 | 対応(読み取り) |
| DuckDB | 対応(読み取り) | 限定的 | 対応(読み取り) |
| Impala | 対応 | 対応 | 限定的 |
6.2 エンジン互換性の詳細分析
Iceberg の優位性: マルチエンジン対応において最も広範。特に Snowflake の Iceberg Tables、Dremio のネイティブ Iceberg 対応、BigQuery の Iceberg 読み取りにより、エンジン間でのデータ共有が容易。
Hudi の優位性: Flink との統合が最も成熟しており、リアルタイムストリーミングパイプラインでの利用に適している。
Delta Lake の優位性: Spark / Databricks との統合が最も深く、パフォーマンス最適化が行き届いている。Databricks Runtime では Delta Lake 固有の最適化(Photon エンジン等)が適用される。
エンジン互換性スコアカード(5段階評価):
Iceberg Hudi Delta Lake
Spark: ★★★★★ ★★★★★ ★★★★★
Trino: ★★★★★ ★★★☆☆ ★★★☆☆
Flink: ★★★★☆ ★★★★★ ★★☆☆☆
Athena: ★★★★★ ★★★★☆ ★★★★☆
BigQuery: ★★★★☆ ★★☆☆☆ ★★★☆☆
Snowflake: ★★★★★ ★☆☆☆☆ ★☆☆☆☆
Databricks: ★★★★☆ ★★★☆☆ ★★★★★
Dremio: ★★★★★ ★☆☆☆☆ ★★☆☆☆
DuckDB: ★★★★☆ ★★☆☆☆ ★★★★☆
総合: ★★★★★ ★★★☆☆ ★★★★☆
7. パフォーマンス比較
7.1 パフォーマンス比較概要
テーブルフォーマットのパフォーマンスは、ワークロードの種類、データ規模、設定、使用するクエリエンジンによって大きく異なる。以下は一般的な傾向を示すものであり、具体的な数値は環境依存であることに留意されたい。
7.2 読み取りパフォーマンス
読み取りパフォーマンスの相対比較(スキャン量が同等の場合):
ポイントルックアップ(単一レコード取得):
Iceberg: ████████░░ (良い - マニフェスト枝刈り)
Hudi (CoW): █████████░ (非常に良い - Record Index)
Hudi (MoR): ██████░░░░ (中程度 - マージオーバーヘッド)
Delta Lake: ████████░░ (良い - DV 適用済み)
フルテーブルスキャン:
Iceberg: █████████░ (非常に良い)
Hudi (CoW): █████████░ (非常に良い)
Hudi (MoR): ██████░░░░ (中程度 - ログマージが必要)
Delta Lake: █████████░ (非常に良い)
パーティションプルーニング付きスキャン:
Iceberg: ██████████ (最良 - 隠しパーティショニング + 統計情報)
Hudi (CoW): ████████░░ (良い)
Hudi (MoR): ███████░░░ (良い - ただしマージオーバーヘッド)
Delta Lake: ████████░░ (良い - 統計情報による最適化)
複雑な分析クエリ(集計・結合):
Iceberg: █████████░ (非常に良い)
Hudi (CoW): ████████░░ (良い)
Hudi (MoR): ██████░░░░ (中程度)
Delta Lake: █████████░ (非常に良い - Databricks 上では最良)
読み取りパフォーマンスの主要因:
| 最適化要素 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| ファイルプルーニング | マニフェスト階層の統計情報 | メタデータテーブル | トランザクションログの統計情報 |
| カラムプルーニング | Parquet/ORC のネイティブ機能 | 同左 | Parquet のネイティブ機能 |
| パーティションプルーニング | 隠しパーティショニング(最も効率的) | 明示的パーティション | 明示的パーティション |
| データスキッピング | min/max 統計、ブルームフィルタ(計画中) | ブルームフィルタ、カラム統計 | min/max 統計、Z-Order |
| キャッシュ | エンジン依存 | エンジン依存 | Databricks: Delta Cache |
7.3 書き込みパフォーマンス
書き込みパフォーマンスの相対比較:
バルクインサート(大量データの初期ロード):
Iceberg: █████████░ (非常に良い)
Hudi: ███████░░░ (良い - Record Key 管理のオーバーヘッド)
Delta Lake: █████████░ (非常に良い)
ストリーミングインサート(マイクロバッチ):
Iceberg: ███████░░░ (良い)
Hudi (MoR): █████████░ (非常に良い - ログ追記のみ)
Delta Lake: ████████░░ (良い)
単一行 UPSERT:
Iceberg: ██████░░░░ (中程度)
Hudi (MoR): ██████████ (最良 - Record Index + ログ追記)
Hudi (CoW): █████░░░░░ (ファイル書き直しのため遅い)
Delta Lake: ███████░░░ (良い - DV + Insert)
バルク UPSERT(大量行の更新):
Iceberg: ████████░░ (良い)
Hudi (MoR): █████████░ (非常に良い)
Hudi (CoW): ██████░░░░ (中程度)
Delta Lake: ████████░░ (良い)
7.4 UPDATE/DELETE パフォーマンス
| 操作 | Iceberg | Hudi (CoW) | Hudi (MoR) | Delta Lake |
|---|---|---|---|---|
| 単一行 DELETE | Delete File 作成 | ファイル書き直し | ログ追記 | DV ビット反転 |
| バルク DELETE | Delete File(s) 作成 | 複数ファイル書き直し | ログ追記 | DV 更新 |
| 単一行 UPDATE | Delete + Insert | ファイル書き直し | ログ追記 | DV + 新行 Insert |
| パーティション DELETE | メタデータのみ更新 | メタデータのみ更新 | メタデータのみ更新 | メタデータのみ更新 |
| 書き込み増幅 | 低(Delete File) | 高(ファイル書き直し) | 低(ログ追記) | 低〜中(DV) |
| 読み取り増幅 | 低〜中 | なし | 高(マージ必要) | 低〜中 |
7.5 メタデータオーバーヘッド
| メタデータ項目 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| テーブル状態の取得 | カタログルックアップ + メタデータファイル読み取り | .hoodie ディレクトリの読み取り | _delta_log の読み取り + チェックポイント |
| ファイルリスティング | 不要(マニフェストに完全記録) | 不要(メタデータテーブル使用時) | 不要(トランザクションログに記録) |
| プランニング時間(10万ファイル) | 秒〜十数秒 | 秒〜数十秒 | 秒〜十数秒 |
| プランニング時間(100万ファイル) | 十数秒〜分 | 数十秒〜数分 | 数十秒〜分 |
| メタデータサイズの増加率 | 中(マニフェスト再利用) | 大(メタデータテーブル) | 中(チェックポイント圧縮) |
7.6 小ファイル問題 (Small File Problem)
小ファイル問題は全フォーマットに共通する課題であるが、対処方法が異なる。
| 小ファイル対策 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 自動コンパクション | 設定可能(外部トリガー) | ネイティブ対応(Inline/Async) | Auto-OPTIMIZE |
| ファイルサイズ制御 | write.target-file-size-bytes | hoodie.parquet.max.file.size | spark.databricks.delta.targetFileSize |
| Bin-packing | Rewrite Data Files アクション | Clustering サービス | OPTIMIZE コマンド |
| ストリーミング時の制御 | コミット間隔調整 | Flushing 間隔調整 | トリガー間隔調整 |
-- Iceberg: 小ファイルのコンパクション
CALL catalog.system.rewrite_data_files(
table => 'db.events',
strategy => 'binpack',
options => map(
'target-file-size-bytes', '134217728', -- 128MB
'min-file-size-bytes', '67108864', -- 64MB
'max-file-size-bytes', '268435456' -- 256MB
)
);
-- Hudi: Inline コンパクション設定
-- hoodie.compact.inline = true
-- hoodie.compact.inline.max.delta.commits = 5
-- hoodie.parquet.max.file.size = 134217728
-- Delta Lake: OPTIMIZE
OPTIMIZE delta.`s3://bucket/warehouse/events`
WHERE event_date >= '2025-01-01';
-- Delta Lake: Auto-OPTIMIZE (Databricks)
ALTER TABLE events
SET TBLPROPERTIES (
'delta.autoOptimize.optimizeWrite' = 'true',
'delta.autoOptimize.autoCompact' = 'true'
);
8. メンテナンス操作比較
8.1 コンパクション
| コンパクション | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| コマンド | rewrite_data_files | Compaction (MoR) / Clustering | OPTIMIZE |
| 戦略 | binpack, sort | 各種 Compaction 戦略 | binpack + Z-Order/Liquid |
| 非同期実行 | 手動スケジュール | Inline / Async / Schedule | Auto-OPTIMIZE / 手動 |
| 増分コンパクション | 対応 | 対応(最も成熟) | 対応 |
| 並行読み取り | 影響なし | 影響なし | 影響なし |
-- Iceberg コンパクション (Sort Order 適用)
CALL catalog.system.rewrite_data_files(
table => 'db.events',
strategy => 'sort',
sort_order => 'event_time ASC NULLS LAST, user_id ASC NULLS LAST',
options => map(
'target-file-size-bytes', '134217728',
'rewrite-all', 'true'
)
);
-- Hudi MoR コンパクション (Spark)
-- spark.read.format("hudi")
-- .option("hoodie.compaction.strategy", "org.apache.hudi.table.action.compact.strategy.LogFileSizeBasedCompactionStrategy")
-- .option("hoodie.compaction.target.io", "512000")
-- .load("s3://bucket/warehouse/events")
-- .write.format("hudi")
-- .option("hoodie.compact.inline", "true")
-- .mode("append")
-- .save("s3://bucket/warehouse/events")
-- Hudi Clustering
-- hoodie.clustering.inline = true
-- hoodie.clustering.inline.max.commits = 4
-- hoodie.clustering.plan.strategy.class = org.apache.hudi.client.clustering.plan.strategy.SparkSizeBasedClusteringPlanStrategy
-- Delta Lake OPTIMIZE with Z-Order
OPTIMIZE delta.`s3://bucket/warehouse/events`
ZORDER BY (user_id, event_type);
-- Delta Lake OPTIMIZE with Liquid Clustering
OPTIMIZE events; -- Liquid Clustering は自動的に適用される
8.2 バキューム / クリーニング
| バキューム操作 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| コマンド | expire_snapshots + remove_orphan_files | Cleaner サービス | VACUUM |
| 古いスナップショットの削除 | expire_snapshots | 自動(保持コミット数設定) | ログの自動期限切れ |
| 孤立ファイルの削除 | remove_orphan_files | Cleaner の一部 | VACUUM |
| デフォルト保持期間 | 5日 | 10コミット / 24時間 | 7日 |
| ドライラン | 対応 | 限定的 | DRY RUN オプション |
| 並行読み取りへの影響 | 保持期間内は安全 | 保持コミット内は安全 | 保持期間内は安全 |
-- Iceberg: スナップショットの期限切れ
CALL catalog.system.expire_snapshots(
table => 'db.events',
older_than => TIMESTAMP '2025-01-01 00:00:00',
retain_last => 10
);
-- Iceberg: 孤立ファイルの削除
CALL catalog.system.remove_orphan_files(
table => 'db.events',
older_than => TIMESTAMP '2024-12-01 00:00:00',
dry_run => true -- まずドライランで確認
);
-- Hudi: Cleaner 設定
-- hoodie.cleaner.policy = KEEP_LATEST_COMMITS
-- hoodie.cleaner.commits.retained = 10
-- hoodie.clean.automatic = true
-- Delta Lake: VACUUM
VACUUM delta.`s3://bucket/warehouse/events` RETAIN 168 HOURS; -- 7日
VACUUM delta.`s3://bucket/warehouse/events` DRY RUN;
8.3 ファイル最適化操作の総合比較
メンテナンス操作の自動化レベル:
手動 半自動 自動
| | |
Iceberg: |--コンパクション--| |
| |--期限切れ---|
| | |
Hudi: | |---コンパクション (Inline/Async)---
| |---クリーニング (自動)---
| |---クラスタリング (Inline/Async)---
Delta Lake: | | |---Auto-OPTIMIZE---
|--VACUUM----| |
| | |---Auto-Compaction---
考察: メンテナンスの自動化は Hudi が最も成熟しており、コンパクション、クリーニング、クラスタリングを inline (書き込みと同時) または async (非同期) で実行できる。Delta Lake も Databricks 上では Auto-OPTIMIZE が充実している。Iceberg は比較的手動でのメンテナンスが必要だが、そのぶんメンテナンス操作の制御性が高い。
9. 相互運用性
9.1 フォーマット間の相互運用の必要性
現実のデータプラットフォームでは、単一のテーブルフォーマットにすべてを統一することが難しい場合がある。異なるチームが異なるフォーマットを採用していたり、クラウドベンダーがサポートするフォーマットが限られていたりするためである。
9.2 Delta Lake UniForm
UniForm は Delta Lake 3.0 で導入された機能で、Delta テーブルのメタデータを Iceberg と Hudi の両方の形式で自動生成する。
+------------------------------------------------------------------+
| UniForm アーキテクチャ |
+------------------------------------------------------------------+
| |
| Delta テーブルへの書き込み |
| | |
| v |
| +------------------+ |
| | Delta Log | (正規のメタデータ) |
| | _delta_log/ | |
| +------------------+ |
| | |
| +----> UniForm 自動生成 |
| | |
| v v |
| +------------------+ +------------------+ |
| | Iceberg Metadata | | Hudi Metadata | |
| | (metadata.json | | (.hoodie/) | |
| | manifest files) | | | |
| +------------------+ +------------------+ |
| | | |
| v v |
| Iceberg 対応エンジン Hudi 対応エンジン |
| で読み取り可能 で読み取り可能 |
| |
| ※ 書き込みは Delta 経由のみ。Iceberg/Hudi からは読み取り専用 |
| |
+------------------------------------------------------------------+
-- UniForm の有効化
CREATE TABLE events (
event_id BIGINT,
event_time TIMESTAMP,
data STRING
) USING delta
TBLPROPERTIES (
'delta.universalFormat.enabledFormats' = 'iceberg,hudi',
'delta.enableIcebergCompatV2' = 'true'
);
-- 既存テーブルへの UniForm 有効化
ALTER TABLE events
SET TBLPROPERTIES (
'delta.universalFormat.enabledFormats' = 'iceberg'
);
UniForm の制約:
- 書き込みは Delta Lake 経由のみ
- Iceberg / Hudi 側からは読み取り専用
- 一部の機能(パーティション進化等)は Iceberg メタデータに反映されない場合がある
- メタデータの同期にわずかな遅延が生じうる
9.3 Apache XTable (旧 OneTable)
Apache XTable は、テーブルフォーマット間のメタデータ変換を双方向で行うオープンソースプロジェクトである。
+------------------------------------------------------------------+
| Apache XTable アーキテクチャ |
+------------------------------------------------------------------+
| |
| ソーステーブル(任意のフォーマット) |
| | |
| v |
| +------------------+ |
| | XTable | |
| | Sync Process | メタデータの変換を実行 |
| | | (データファイルはそのまま) |
| +--------+---------+ |
| | |
| +-----+------+------+ |
| | | | |
| v v v |
| Iceberg Hudi Delta |
| Metadata Metadata Metadata |
| |
| ※ データファイル自体は共有。メタデータのみが変換される |
| ※ 双方向の同期が可能 |
| |
+------------------------------------------------------------------+
# XTable 設定例 (xtable-config.yaml)
sourceFormat: ICEBERG
targetFormats:
- DELTA
- HUDI
datasets:
- tableBasePath: s3://bucket/warehouse/events
tableName: events
partitionSpec: days(event_time)
# XTable 同期の実行
java -jar xtable-utilities.jar --datasetConfig xtable-config.yaml
XTable の特徴:
- データファイルは一切コピーしない(メタデータのみの変換)
- 双方向の変換が可能(Iceberg <-> Hudi <-> Delta)
- インクリメンタル同期対応
- Apache Incubator プロジェクト
9.4 相互運用性の比較
| 相互運用方式 | UniForm | XTable |
|---|---|---|
| 開発元 | Databricks | Onehouse (Apache Incubator) |
| 方向性 | Delta -> Iceberg/Hudi(片方向) | 双方向 |
| データコピー | なし | なし |
| メタデータ同期 | 自動(コミット時) | 手動/スケジュール |
| 書き込み制約 | Delta 経由のみ | ソースフォーマット経由のみ |
| 成熟度 | GA (Databricks) | Incubator |
| 遅延 | 最小 | バッチ実行による遅延 |
10. エコシステムとツーリング
10.1 カタログソリューション
| カタログ | Iceberg | Hudi | Delta Lake | 特徴 |
|---|---|---|---|---|
| Apache Polaris | ネイティブ | 非対応 | 非対応 | Snowflake 発の OSS Iceberg カタログ |
| Nessie | ネイティブ | 非対応 | 非対応 | Git-like バージョニング |
| Unity Catalog | 対応 | 対応 | ネイティブ | Databricks 発の統合カタログ(OSS化済み) |
| AWS Glue | 対応 | 対応 | 対応 | AWS マネージドカタログ |
| Hive Metastore | 対応 | 対応 | 対応 | 従来型のカタログ |
| Gravitino | 対応 | 対応 | 対応 | Apache Incubator のメタデータレイク |
10.2 データガバナンスツール
| ツール | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| Apache Atlas | 対応 | 対応 | 対応 |
| Datahub | 対応 | 対応 | 対応 |
| OpenMetadata | 対応 | 対応 | 対応 |
| Amundsen | 対応 | 対応 | 対応 |
| Collibra | 対応 | 対応 | 対応 |
10.3 ETL / データ統合ツール
| ツール | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| Apache Airflow | 対応 | 対応 | 対応 |
| dbt | 対応 (dbt-spark, dbt-trino) | 対応 (dbt-spark) | 対応 (dbt-databricks, dbt-spark) |
| Airbyte | 対応 | 対応 | 対応 |
| Fivetran | 対応 | 対応 | 対応 |
| AWS Glue ETL | ネイティブ | ネイティブ | ネイティブ |
11. コミュニティと採用状況
11.1 主要採用企業
Apache Iceberg の採用企業
| 企業 | ユースケース |
|---|---|
| Netflix | 開発元。データレイク全体の基盤として使用 |
| Apple | 大規模データ分析基盤 |
| データレイクハウスの標準フォーマット | |
| Airbnb | 分析基盤のテーブルフォーマット |
| Stripe | 決済データの分析基盤 |
| Adobe | データプラットフォーム |
| Expedia | 旅行データの分析 |
| Snowflake | Iceberg Tables として商用提供 |
| AWS | Athena, EMR, Glue でネイティブサポート |
Apache Hudi の採用企業
| 企業 | ユースケース |
|---|---|
| Uber | 開発元。ライドシェアデータの upsert 処理 |
| Amazon / AWS | EMR でネイティブサポート。内部でも広範に利用 |
| ByteDance (TikTok) | 大規模なデータパイプライン |
| Robinhood | 金融取引データのリアルタイム処理 |
| Disney+ Hotstar | ストリーミングデータの処理 |
| GE Aviation | IoT データの管理 |
| Walmart | 小売データのリアルタイム分析 |
Delta Lake の採用企業
| 企業 | ユースケース |
|---|---|
| Databricks | 開発元。全製品の基盤 |
| Microsoft | Azure Synapse、Fabric でネイティブサポート |
| Comcast | メディアデータの分析 |
| Riot Games | ゲームデータの分析 |
| Shell | エネルギーデータの管理 |
| HP | IoT / 製造データの分析 |
| Nationwide | 保険データの分析 |
11.2 クラウドプロバイダーのサポート
| クラウドサービス | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| AWS EMR | ネイティブ | ネイティブ | ネイティブ |
| AWS Athena | ネイティブ | ネイティブ | ネイティブ |
| AWS Glue | ネイティブ | ネイティブ | ネイティブ |
| AWS Redshift Spectrum | 対応 | 対応 | 対応 |
| Azure Synapse | 対応 | 対応 | ネイティブ |
| Azure Fabric | 対応 | 限定的 | ネイティブ |
| GCP BigQuery | ネイティブ (BigLake) | 限定的 | 対応 (BigLake) |
| GCP Dataproc | 対応 | 対応 | 対応 |
| Snowflake | ネイティブ (Iceberg Tables) | 非対応 | 非対応 |
| Databricks | 対応 (UniForm) | 対応 | ネイティブ |
11.3 業界トレンド分析
業界採用トレンド(2022-2025):
市場シェアの推移(概算):
2022: Iceberg ████████░░░░░░░░░░░░ 30%
Hudi ██████░░░░░░░░░░░░░░ 25%
Delta ████████████░░░░░░░░ 45%
2023: Iceberg ████████████░░░░░░░░ 38%
Hudi █████░░░░░░░░░░░░░░░ 20%
Delta ████████████░░░░░░░░ 42%
2024: Iceberg ██████████████░░░░░░ 45%
Hudi ████░░░░░░░░░░░░░░░░ 17%
Delta ████████████░░░░░░░░ 38%
2025: Iceberg ████████████████░░░░ 50%
Hudi ████░░░░░░░░░░░░░░░░ 15%
Delta ███████████░░░░░░░░░ 35%
※ 上記は市場調査レポートおよび公開情報に基づく推定値
トレンド分析:
- Iceberg は 2023 年以降、急速にシェアを拡大。Snowflake の Iceberg Tables 対応、AWS の積極的なサポート、Google BigQuery の対応が主因
- Delta Lake は Databricks エコシステムに支えられ安定したシェアを維持しているが、相対的には Iceberg にシェアを奪われている
- Hudi はニッチな高頻度 upsert ユースケースで堅実な需要があるが、汎用的な採用では Iceberg に押される傾向
12. マイグレーション戦略
12.1 フォーマット間マイグレーションの方法
方法1: メタデータのみの変換(推奨)
データファイルを再書き込みせず、メタデータのみを新フォーマットで作成する方法。
手順:
1. XTable / UniForm を使用してメタデータを変換
2. 新フォーマットでの読み取りテスト
3. 書き込みパイプラインを新フォーマットに切り替え
4. 旧フォーマットのメタデータをクリーンアップ
方法2: CTAS(Create Table As Select)
-- Hudi -> Iceberg (CTAS)
CREATE TABLE catalog.db.events_iceberg
USING iceberg
PARTITIONED BY (days(event_time))
AS SELECT
event_id, event_time, user_id, event_type, payload
FROM hudi_catalog.db.events_hudi;
-- Delta -> Iceberg (CTAS)
CREATE TABLE catalog.db.events_iceberg
USING iceberg
PARTITIONED BY (days(event_time))
AS SELECT * FROM delta.`s3://bucket/events_delta`;
-- Iceberg -> Delta (CTAS)
CREATE TABLE events_delta
USING delta
PARTITIONED BY (event_date)
AS SELECT *, CAST(event_time AS DATE) AS event_date
FROM catalog.db.events_iceberg;
方法3: Iceberg のインプレースマイグレーション
-- 既存の Parquet/Hive テーブルを Iceberg にインプレース変換
CALL catalog.system.migrate('db.legacy_events');
-- Iceberg への Snapshot Import(データコピーなし)
CALL catalog.system.add_files(
table => 'db.events_iceberg',
source_table => 'db.legacy_events'
);
12.2 マイグレーション戦略の比較
| マイグレーション方式 | データコピー | ダウンタイム | 複雑度 | 推奨度 |
|---|---|---|---|---|
| メタデータ変換 (XTable) | なし | 最小 | 低 | 高 |
| CTAS | あり(全データ) | あり | 低 | 中(小規模向け) |
| Iceberg migrate | なし | 最小 | 低 | 高(Iceberg への移行時) |
| 段階的マイグレーション | 新規データのみ | なし | 中 | 高(大規模向け) |
| Dual-write | あり(増分) | なし | 高 | 中 |
12.3 マイグレーション時の注意点
- テスト計画: 本番データのサブセットで事前に読み書きテストを実施する
- パフォーマンス検証: マイグレーション前後でクエリパフォーマンスを比較する
- メタデータの整合性: 特にパーティション仕様、スキーマ、統計情報の整合性を確認する
- ロールバック計画: マイグレーション失敗時のロールバック手順を事前に定義する
- 並行運用期間: 新旧フォーマットの並行運用期間を設け、段階的に移行する
13. 選定フレームワーク
13.1 意思決定フロー
+-------------------+
| テーブルフォーマット |
| の選定 |
+--------+----------+
|
+----------------+----------------+
| |
Databricks を Databricks 以外の
主要プラットフォーム プラットフォームを使用
として使用? (またはマルチエンジン)
| |
v |
+-----------+ |
| Delta Lake| +------------+------------+
| を推奨 | | |
+-----------+ | |
高頻度 upsert / 汎用的な分析
CDC が主要 ワークロード
ワークロード?
| |
v v
+-----------+ +-----------+
| Hudi | | Iceberg |
| を推奨 | | を推奨 |
+-----------+ +-----------+
13.2 Iceberg を選ぶべき場合
最適なシナリオ:
- マルチエンジン環境: Spark + Trino + Flink + その他のエンジンを併用する場合
- オープン標準重視: ベンダーロックインを最小化したい場合
- パーティション進化が必要: ビジネスの変化に伴いパーティションスキームを頻繁に変更する場合
- 大規模テーブル: 数十TB〜PBクラスのテーブルで、メタデータの効率的な管理が重要な場合
- Snowflake との統合: Snowflake をデータウェアハウスとして使用し、データレイクとのシームレスな連携が必要な場合
- Git-like ガバナンス: Nessie による分岐・マージベースのデータガバナンスが必要な場合
- WAP パターン: Write-Audit-Publish パターンでデータ品質を管理したい場合
コード例: Iceberg のパーティション進化を活用するパイプライン
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.config("spark.sql.catalog.lakehouse", "org.apache.iceberg.spark.SparkCatalog") \
.config("spark.sql.catalog.lakehouse.type", "rest") \
.config("spark.sql.catalog.lakehouse.uri", "https://polaris.example.com/api/catalog") \
.getOrCreate()
# テーブル作成(日単位パーティション)
spark.sql("""
CREATE TABLE IF NOT EXISTS lakehouse.analytics.user_events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
properties MAP<STRING, STRING>
) USING iceberg
PARTITIONED BY (days(event_time))
TBLPROPERTIES (
'write.format.default' = 'parquet',
'write.parquet.compression-codec' = 'zstd',
'write.metadata.delete-after-commit.enabled' = 'true',
'write.metadata.previous-versions-max' = '100'
)
""")
# データ増加に伴いパーティションを時間単位に変更
spark.sql("""
ALTER TABLE lakehouse.analytics.user_events
ADD PARTITION FIELD hours(event_time)
""")
spark.sql("""
ALTER TABLE lakehouse.analytics.user_events
DROP PARTITION FIELD days(event_time)
""")
# 既存データの再書き込みは不要!
13.3 Hudi を選ぶべき場合
最適なシナリオ:
- 高頻度 upsert: 毎分〜毎秒のペースでレコードの挿入・更新が発生する場合
- CDC パイプライン: データベースの変更をリアルタイムにデータレイクに反映する場合
- インクリメンタル処理: 変更分のみを効率的に処理するパイプラインが必要な場合
- Flink ストリーミング: Apache Flink をストリーミングエンジンとして使用する場合
- レコードレベルインデックス: 主キーベースの効率的なレコード検索が必要な場合
コード例: Hudi による CDC パイプライン
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer") \
.config("spark.sql.catalog.spark_catalog",
"org.apache.spark.sql.hudi.catalog.HoodieCatalog") \
.getOrCreate()
# CDC データの upsert (MoR テーブル)
cdc_options = {
'hoodie.table.name': 'user_profiles',
'hoodie.datasource.write.table.type': 'MERGE_ON_READ',
'hoodie.datasource.write.recordkey.field': 'user_id',
'hoodie.datasource.write.precombine.field': 'updated_at',
'hoodie.datasource.write.operation': 'upsert',
'hoodie.datasource.write.payload.class':
'org.apache.hudi.common.model.DefaultHoodieRecordPayload',
# インデックス設定
'hoodie.index.type': 'RECORD_INDEX',
# コンパクション設定
'hoodie.compact.inline': 'true',
'hoodie.compact.inline.max.delta.commits': '5',
# クリーニング設定
'hoodie.clean.automatic': 'true',
'hoodie.cleaner.commits.retained': '10',
}
cdc_df.write.format("hudi") \
.options(**cdc_options) \
.mode("append") \
.save("s3://bucket/warehouse/user_profiles")
# インクリメンタルクエリで変更分を取得
incremental_df = spark.read.format("hudi") \
.option("hoodie.datasource.query.type", "incremental") \
.option("hoodie.datasource.read.begin.instanttime", "20250101120000") \
.load("s3://bucket/warehouse/user_profiles")
13.4 Delta Lake を選ぶべき場合
最適なシナリオ:
- Databricks 中心の環境: Databricks を主要なデータプラットフォームとして使用する場合
- Spark 重視: Apache Spark が唯一のクエリエンジンである場合
- Liquid Clustering: Z-Order やLiquid Clustering によるデータレイアウト最適化が重要な場合
- Delta Sharing: 組織間でのセキュアなデータ共有が必要な場合
- シンプルさ: 設定の少なさと「そのまま動く」体験を重視する場合
- Photon エンジン: Databricks Photon による高速クエリ実行が必要な場合
コード例: Delta Lake の Liquid Clustering を活用
from pyspark.sql import SparkSession
from delta.tables import DeltaTable
spark = SparkSession.builder \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog",
"org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()
# Liquid Clustering を使用したテーブル作成
spark.sql("""
CREATE TABLE IF NOT EXISTS events (
event_id BIGINT,
event_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
region STRING,
payload STRING
) USING delta
CLUSTER BY (event_time, user_id, region)
TBLPROPERTIES (
'delta.enableChangeDataFeed' = 'true',
'delta.enableDeletionVectors' = 'true'
)
""")
# OPTIMIZE はクラスタリングを自動的に適用
spark.sql("OPTIMIZE events")
# クラスタリングキーの変更(パーティション進化の代替)
spark.sql("ALTER TABLE events CLUSTER BY (region, event_type)")
# Change Data Feed の利用
changes_df = spark.read.format("delta") \
.option("readChangeFeed", "true") \
.option("startingVersion", 5) \
.option("endingVersion", 10) \
.table("events")
changes_df.filter("_change_type IN ('update_postimage', 'insert')").show()
13.5 選定マトリクス
| 評価軸 | 重要度 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|---|
| マルチエンジン対応 | ★★★★★ | ◎ | △ | ○ |
| Spark 統合 | ★★★★☆ | ◎ | ◎ | ◎ |
| Flink 統合 | ★★★☆☆ | ○ | ◎ | △ |
| Trino 統合 | ★★★★☆ | ◎ | ○ | ○ |
| 高頻度 upsert | ★★★★☆ | ○ | ◎ | ○ |
| CDC 対応 | ★★★★☆ | ○ | ◎ | ○ |
| パーティション進化 | ★★★★☆ | ◎ | △ | × (Liquid で代替) |
| スキーマ進化 | ★★★★☆ | ◎ | ○ | ○ |
| タイムトラベル | ★★★☆☆ | ◎ | ○ | ◎ |
| 同時実行制御 | ★★★☆☆ | ○ | ○ | ○ |
| ブランチング | ★★☆☆☆ | ◎ | × | × |
| メンテナンス自動化 | ★★★★☆ | △ | ◎ | ○ (Databricks) |
| コミュニティの広さ | ★★★★☆ | ◎ | ○ | ○ |
| ドキュメント品質 | ★★★☆☆ | ○ | ○ | ◎ |
| 学習コスト | ★★★☆☆ | ○ | △ | ◎ |
| クラウドサポート | ★★★★★ | ◎ | ○ | ○ |
凡例: ◎ = 優れている / ○ = 良い / △ = 可能だが限定的 / × = 非対応 or 弱い
14. 今後の収束トレンド
14.1 フォーマット間の機能収束
2024〜2025 年にかけて、3つのフォーマットは機能面で急速に収束している。
機能収束のタイムライン:
2020: 各フォーマットが独自の強みに特化
Iceberg: パーティション進化
Hudi: upsert / CDC
Delta: Spark 統合
2022: 基本機能の均質化が始まる
全フォーマット: ACID, スキーマ進化, タイムトラベル
2024: 高度な機能の収束
行レベル更新: Iceberg (Delete Files), Hudi (MoR), Delta (DV)
CDC: 全フォーマットで対応
Z-Order / Clustering: 全フォーマットで対応
2025-2026 (予測):
- 相互運用性の成熟(UniForm, XTable)
- REST Catalog 標準の普及
- AI/ML ワークロード対応の強化
- リアルタイム対応の強化
14.2 Iceberg が業界標準に近づく動き
以下の要因により、Iceberg が事実上の業界標準になりつつある:
- Snowflake の Iceberg Tables: Snowflake が Iceberg を外部テーブルフォーマットとしてネイティブサポート
- Google BigQuery: BigLake を通じた Iceberg 対応
- AWS の全面サポート: Athena, EMR, Glue, Redshift Spectrum でのネイティブ対応
- Databricks の UniForm: Delta テーブルを Iceberg として読み取り可能にする機能
- REST Catalog 標準化: Iceberg REST Catalog 仕様がカタログの相互運用標準になりつつある
- Apache Polaris: Snowflake がオープンソース化した Iceberg カタログ
14.3 将来の技術動向
| トレンド | 説明 | 各フォーマットへの影響 |
|---|---|---|
| AI/ML ワークロード対応 | 特徴量ストア、モデル管理との統合 | 全フォーマットで対応が進む |
| リアルタイム化 | サブ秒レベルのデータ鮮度 | Hudi が先行、Iceberg/Delta が追随 |
| ストレージ最適化 | 圧縮、エンコーディングの進化 | 全フォーマットで継続的改善 |
| 自動チューニング | AI ベースの自動最適化 | Databricks (Delta) が先行 |
| セキュリティ強化 | 行・カラムレベルのアクセス制御 | カタログ層での実装が主流 |
| マルチリージョン | グローバルなレプリケーション | 全フォーマットで課題 |
15. まとめと推奨マトリクス
15.1 総合評価
| 評価カテゴリ | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| アーキテクチャ | ◎ 階層的メタデータ、スケーラブル | ○ Timeline ベース、柔軟 | ○ シンプルなログ構造 |
| 機能の網羅性 | ◎ パーティション進化、ブランチング | ◎ CDC、upsert、インデックス | ○ Liquid Clustering、DV |
| パフォーマンス | ◎ 読み取り最適化 | ◎ 書き込み最適化 | ◎ Databricks 上で最適化 |
| エコシステム | ◎ 最も広範 | ○ Flink に強い | ○ Databricks に最適化 |
| コミュニティ | ◎ 急成長中 | ○ 安定 | ○ Databricks 主導 |
| 将来性 | ◎ 業界標準化の流れ | ○ ニッチ領域で堅実 | ○ Databricks エコシステム内で堅実 |
15.2 推奨シナリオ別サマリー
+------------------------------------------------------------------+
| 推奨マトリクス |
+------------------------------------------------------------------+
| |
| シナリオ 推奨フォーマット |
| ─────────────────────────────────────── ───────────────── |
| マルチエンジン環境 → Iceberg |
| Snowflake + データレイク連携 → Iceberg |
| 大規模テーブル (PB級) → Iceberg |
| パーティション変更が頻繁 → Iceberg |
| オープン標準・ベンダー中立 → Iceberg |
| Git-like データガバナンス → Iceberg + Nessie |
| |
| 高頻度 upsert (毎分以上) → Hudi (MoR) |
| DB CDC → データレイク パイプライン → Hudi |
| Flink ストリーミング → Hudi |
| インクリメンタル処理重視 → Hudi |
| 主キーベースの効率的検索 → Hudi (Record Index) |
| |
| Databricks が主要プラットフォーム → Delta Lake |
| Spark オンリーの環境 → Delta Lake |
| Liquid Clustering による最適化 → Delta Lake |
| Delta Sharing によるデータ共有 → Delta Lake |
| Microsoft Azure 中心の環境 → Delta Lake |
| 最小限の設定で「すぐ動く」を重視 → Delta Lake |
| |
+------------------------------------------------------------------+
15.3 最終的な推奨
2025年の時点で、新規プロジェクトにおいてデフォルトの選択肢として推奨するのは Apache Iceberg である。その理由は以下の通り:
- エンジン互換性の広さ: 現在の主要なクエリエンジン・クラウドサービスのほぼすべてで Iceberg がサポートされている
- ベンダー中立性: ASF のオープンガバナンスにより、特定ベンダーへのロックインリスクが最小
- パーティション進化: データの成長に伴う柔軟なパーティション変更が可能
- 業界の収束: Snowflake、AWS、Google、Databricks (UniForm) のすべてが Iceberg をサポートする方向に動いている
- REST Catalog 標準: カタログの相互運用性が高い
ただし、以下の場合は Hudi または Delta Lake を選択すべきである:
- Hudi: 高頻度 upsert / CDC が主要ワークロードで、Flink との統合が重要な場合
- Delta Lake: Databricks を主要プラットフォームとして使用し、Liquid Clustering や Photon の恩恵を最大限に受けたい場合
最終的な選択は、組織の技術スタック、ワークロード特性、運用体制に基づいて行うべきである。また、UniForm や XTable の成熟により、フォーマットの切り替えコストは低下傾向にあるため、現時点の選択が永続的な制約になるリスクは低減している。
15.4 今後のウォッチポイント
- Apache Iceberg v3 仕様: Row-level updates の進化、新しいメタデータ機能
- Delta Lake Kernel: エンジン非依存の読み取り/書き込みライブラリの成熟
- Hudi 1.x: アーキテクチャ刷新による競争力の変化
- Apache XTable の GA: 相互運用性の成熟度
- REST Catalog の標準化: カタログの相互運用性の進展
- AI/ML ワークロードへの対応: 各フォーマットの AI/ML 統合の深度
付録
A. 用語集
| 用語 | 説明 |
|---|---|
| テーブルフォーマット | データファイル群の上に論理的なテーブル抽象を提供する仕様 |
| レイクハウス | データレイクとデータウェアハウスを統合するアーキテクチャ |
| ACID | Atomicity, Consistency, Isolation, Durability の頭字語 |
| OCC | Optimistic Concurrency Control(楽観的同時実行制御) |
| CoW | Copy-on-Write。更新時にファイル全体を書き直すアプローチ |
| MoR | Merge-on-Read。更新をログに追記し、読み取り時にマージするアプローチ |
| CDC | Change Data Capture。データソースの変更を検知・転送する技術 |
| DV | Deletion Vector。Delta Lake の行レベル削除メカニズム |
| WAP | Write-Audit-Publish。データ品質検証を挟む書き込みパターン |
| MVCC | Multi-Version Concurrency Control(多版同時実行制御) |
B. 参考文献
- Apache Iceberg 公式ドキュメント: https://iceberg.apache.org/
- Apache Hudi 公式ドキュメント: https://hudi.apache.org/
- Delta Lake 公式ドキュメント: https://delta.io/
- Apache XTable (OneTable): https://xtable.apache.org/
- Databricks UniForm: https://docs.databricks.com/en/delta/uniform.html
- Apache Polaris: https://polaris.apache.org/
- Nessie: https://projectnessie.org/
C. 変更履歴
| 日付 | バージョン | 変更内容 |
|---|---|---|
| 2026-04-11 | 1.0 | 初版作成 |
本ドキュメントは AI (Claude) を利用して生成されました。記載内容は 2025 年までの公開情報に基づいており、最新の状況は各プロジェクトの公式ドキュメントをご確認ください。