3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Iceberg v4 Single File Commit の設計思想とメタデータ構造について調べてみた

Last updated at Posted at 2025-12-09

Iceberg V4でSingle File Commitsの提案がされているらしい。
特に性能面では重要な提案っぽいが、詳しく書かれた記事があまりなかったので調べてみた。

概要

Apache Iceberg コミュニティは、v4 に向けて 「Single File Commit」 というメタデータ構造の刷新の提案が出されている。
以下の記事にあるように、背景には、近年増えているストリーミング/マイクロバッチ処理に現行の Iceberg が十分対応できていないという問題がある模様。

Every commit to an Iceberg table today creates at least two new metadata files: one for the updated manifest list, and another for any changed manifests. In fast-moving environments—like streaming ingestion or micro-batch pipelines—this adds up quickly.

このような問題に対応するのが「Single File Commit」ということらしい。

元資料

Proposal

Youtubeでの議論

これまでのIcebergの問題点

  1. コミット処理が重い
    • metadata.json、manifest list、manifest file の3つを毎回書き込む必要があり、特に小規模書き込みではメタデータ生成がコミットのボトルネックになる。
  2. マニフェストリスト(ManifestList) と マニフェスト(Manifest) の二重構造が複雑
    • 両者を区別する現行設計がコードを複雑化し、非パーティション列のメトリクスをスキャン計画に活かせない。
  3. 削除操作が非効率でキャッシュも難しい
    • 削除対象を含む manifest をまるごと再生成する必要があり、場合によっては全 manifest を書き換えることになる。これによりメタデータ変更がテーブルサイズに比例し、manifest キャッシュも困難。

これらの問題を緩和するために、V4 向けの新しいメタデータ構造を提案している。
V4では マニフェストリストを廃止し、特別な種類のマニフェストである Root Manifest に置き換え、さらに削除ベクターをマニフェストに適用できるようにするとのこと。

この記事がわかりやすく変更点を図解してくれてた。

image.png

このProposalのゴール

長々と書かれているが、削除・更新時に参照するファイルを減らすこと、また、ファイル変更の検知をRoot Manifestからできるようにすることが主題のようにみえる。

  1. 無駄なメタデータ書き込みの増幅(write amplification)を減らす
    • 小規模な操作では、クライアント側で 1 つの新しいメタデータファイルを書くだけでよくなるようにする。
    • マニフェストのエントリにおける削除/更新において、メタデータの書き込みの増幅(write amplification)を減らす。
  2. 操作の規模に応じた量だけ、必要最小限のマニフェストを書き出すようにする
    • 新しいスナップショットを生成する際、書き込まれるマニフェストの数は、理想的には操作の規模(追加・削除されたファイル数)に比例する。
    • 新しいスナップショットのメタデータを読み込む際、もしエンジンが前のスナップショットのメタデータを読み込みキャッシュしている場合、新しいスナップショットのメタデータ構築のために読むマニフェスト数も、DML 操作の規模に比例する。
      • これにより、マニフェストのキャッシュ性を向上させる。
  3. メトリクスの集約
    • マニフェストリストとは異なり、新しいトップレベルのマニフェストは、すべての子マニフェストの集計メトリクスを持つ。
  4. Root Manifest はテーブルに対する最後の変更を反映する
    • どのような操作による変更も、Root Manifest に対して行われた変更だけで表現される。

metadata.jsonを消す目的ではないとのこと

Proposal

以下、具体的なv4の仕様について記載していく。

新しいスナップショットの基本構造は以下の通り、Root Manifest(ルートマニフェスト) から始まる。
writer は常に 新しい Root Manifest を作成し、前の Root Manifest を置き換える 必要があり、その中に今回の操作によって生じた変更内容を記録する。

  • Data Manifest
  • Delete Manifest
  • Data File
  • Data Delete Vector(Data DV)
  • Manifest Delete Vector(Manifest DV)

※ V3まで存在したManifest List は使用されなくなる。

image.png

ツリー階層を 2 段(Root → Leaf)に制限

Iceberg v4 の提案では、マニフェストの階層をRoot Manifest → Leaf Manifest の 2 層構造に固定 している。
これは、ライター側が 短期的には高速に見える書き方 をしてしまい、その結果として読み取りが遅くなったり、メタデータ管理が破綻することを防ぐためとのこと。

制限をしない場合、Writerは前のマニフェストを参照するマニフェストを無限に作ることが可能。
結果として書込みは早くなるが、マニフェストチェーンが深くなると読み込み性能を著しく下げる。
また、コンパクションのコストも高くなるとのこと。

2階層であっても理論上は10億(billion)ファイル規模でも問題なくスケールするらしい。

Commit Procedure

データファイルやマニフェストの更新についての仕様が書かれているが、Examplesを見て動作を理解する方が早いので省略。
大事な部分なので本当は省略はダメなんだけどまぁ。。

Commit Procedure > Any new commit starts by using the information in the previous snapshot’s Root manifest file, this file is then modified based on the changes being applied by the new commit. > [Adding data files / delete files] > A new Root Manifest is created with either an ADDED Data File entry or a new ADDED Data Manifest Entry mapping to a new leaf Data Manifest with the ADDED Data File entry. The engine can determine the optimal layout for the given operation. All previously existing entries are marked as EXISTING. The same procedure is used for Equality Deletes or Delete Vectors. >[Removing a data file / delete file or adding a Delete Vector for a Root Manifest Data File] > A new Root Manifest is created with either an ADDED Delete Vector which removes the data or delete file from a child manifest. We do not allow the copy on write behavior (Merging Snapshot Producer) of removing and adding a child manifest with a net change to the data (including completely deleting a leaf manifest.) [y][z][aa]Whenever a change is made to leaf manifests, it should be marked by newly added Manifest Delete Vectors[ab][ac]. Manifests (or delete vectors) which have not changed in the commit can be compacted or removed. > [Manifest Compaction] > During any commit, existing Data Files, Manifests and Manifest Delete Vectors can be combined to reduce the total number of children under the root manifest. For example, two existing Data Manifests can be combined into a single Data Manifest which would also be marked as existing[ad][ae][af]. Any compactions performed must not create files which cause a net change to table state. Combining an existing delete vector with its target is allowed, but combining entries for new deletes produced or new data files created in the snapshot with an existing manifest to create a new manifest is not allowed.

Examples

ExamplesではAppend, Remove, Overwride, Row Delta, Compactionに関する各ファイル追加削除の流れが記載されている。

Append Files

Appends To the Root Manifest

Root Manifest は毎回 “追記更新” のように書き換えられ、既存のマニフェストは existing として保持しつつ、新しいデータファイルだけ追加するという方式でテーブルが更新されている。

  • Snapshot 1
    • テーブルには 3 つのデータファイルが存在している。
  • Snapshot 2
    • 新しい Root Manifest を作り直し、既存のデータマニフェスト(Snapshot 1 の内容)を existing として保持
    • 新しいデータファイル D4 を追加
    • これによりテーブルに D4 が追加される。
  • Snapshot 3
    • 再び Root Manifest を書き換え、
    • 前の Manifest(Snapshot 2 の内容)を existing として保持
    • 新しいデータファイル D5 の追加エントリを追加
    • これによりテーブルに D5 が追加される。

image.png

Appends to the Root Manifest using new Data Manifests

大量のデータ追加(append)が必要な場合、新しい子マニフェスト(Data Manifest)を直接追加する方式 も従来どおり利用できる。

Root ManifestがManifest Listの役割を担っているだけで、基本的にはV3と同じ動作である。

  • Snapshot 1
    • Root Manifest A → Data Manifest M1 を 1 つ持つ(ADDED)
    • M1 には 3 つのデータファイル D1, D2, D3 が含まれる
  • Snapshot 2
    • Root Manifest B は M1 を existing として保持
    • 新たに ADDED の Data Manifest M2 を追加
    • M2 には D4, D5, D6 の 3 つのデータファイルが含まれる
      image.png

Remove Files

Removing a File From the Root Manifest

Root Manifest 内のファイルは、新しい Root Manifest を作成し、そのファイルを DELETED としてマークすることで削除できる。

  • Snapshot 1
    • Root Manifest に D1, D2 の 2 つの既存ファイルがある。
  • Snapshot 2
    • D1 は削除されるため DELETED として記録される。
    • D2 は変更されず、existing のまま残る。

image.png

Removing a File From a Leaf Manifest

Leaf Manifest(データマニフェスト)内の特定ファイルを削除する場合、そのマニフェストを直接書き換えるのではなく、Manifest Delete Vector(DV)を新しく作成し、該当行を削除済みとしてマークする。

  • Snapshot 1
    • Root Manifest A → Data Manifest M1 を 1 つ参照
    • M1 にはデータファイル D1, D2, D3 の3行がある
  • Snapshot 2(D2 の削除)
    • M1 のエントリはそのまま保持(existing)
    • 新たに Manifest Delete Vector DV1 を追加
    • DV1 は「M1 の ordinal 1(2行目 = D2)」が削除されたことを示す

image.png

Delete Vectorはv3から存在し、Data Fileに紐付き仕様だが、Manifest Delete Vectorはマニフェストに紐付くという部分がこれまでと違うところ。
https://zenn.dev/iceberg/articles/52f7e8db8cc229

Overwrite Files

Overwrite Files in Root Manifest

Overwrite(追加と削除を同時に行う操作) をRoot Manifest のエントリを書き換えるだけで実現できる。
追加のマニフェストファイルを作らずに、Root Manifest の更新だけで完結する。

  • Snapshot 1
    • Root Manifest に D1 という 1 つのデータファイルが記録されている。
  • Snapshot 2
    • Root Manifest を書き換え、D1 を削除(removed)D2 を追加(added)という Overwrite 処理を行う。
      • つまり、D1 → D2 に置き換わる。
  • Snapshot 3
    • Snapshot 2 で追加された D2 を削除し、新しい別のファイル(D3 など)を追加
    • この操作も Root Manifest の更新だけで表現される。

image.png

Overwrite Files inLeaf Manifest

Overwrite は Root Manifest だけでなく、Leaf Manifest(Data Manifest)内のエントリを DV(Manifest Delete Vector)で削除し、置き換えファイルを Root Manifest で追加する という形でも実現できる。

  • Snapshot 1
    • Root Manifest → Data Manifest M1 を参照
    • M1 には D1, D2, D3 の 3 つのデータファイルが含まれている
  • Snapshot 2(D2 の置き換え)
    • M1 は変更せずにそのまま保持(既存のまま)
    • 代わりに Manifest Delete Vector DV1 を追加しM1 の 2 番目の行(D2)を “削除” とマークする
    • 置き換え用の新しいデータファイル D4 はRoot Manifest レベルで追加される

image.png

Row Delta

Root Manifest Only Row Delta

Row Delta(行単位の更新) は、Root Manifest レベルでFile Delete Vector(DV)を追加してデータファイル内の行を削除扱いにし新しいデータファイルを追加することで実現できる。

  • Snapshot 1
    • Root Manifest に D1 という 1 つのデータファイルだけが含まれている。
  • Snapshot 2(Row Delta)
    • D1 の行の一部を削除するために File Delete Vector DV1 を追加
    • 追加すべき新しい行は 新しいデータファイル D2 に格納し、Root Manifest に追加する

image.png

A Complex Row Delta with Modified Delete Vectors

既に Delete Vector が存在する Snapshot に対しても Row Delta(行更新)を適用できる。
その場合、既存の delete files(delete manifest の DV)は、新しい Delete Vector に置き換えられる。
新しい削除情報は、新規 delete manifest か Root Manifest に追加し、更新後の行データは、新しい data file として追加される。

image.png

Manifest Compaction

Manifest Compaction During an Append

Delete Vector(DV)は、既存のマニフェストに対して適用することができ、その結果できあがったマニフェストを “EXISTING(既存)” として扱う限り、マニフェストのコンパクション(統合)も実施可能 である。

下記の例では append(データ追加)操作の中で DV の適用とマニフェストのコンパクションが行われているが、これは どの Snapshot 更新操作においても同様に行うことができる。
image.png

所感

正直、最初にこの proposal を見たときは「メタデータ構造をちょっといじる話でしょ?」くらいに思っていたのですが、読み込めば読むほど、これは Iceberg をバッチ寄りのテーブルフォーマットからストリーム時代のストレージレイヤに引き上げるための大手術 に見えてきました。
実際、Databricks は Delta Lake House → Real-Time Lakehouse を掲げ、Snowflake は Snowpipe Streaming / Unistore を推し進めている状況。
時間ではなく秒単位で更新されるテーブルに耐えられるメタデータ構造が求められているのだと思います。
そして、Iceberg がこれに対応するための提案が今回の「Single File Commits」なのかなと。

最近の議論

Single File Commitsでは、マニフェストにPartition Tupleを含めるべきかどうかが議論になっているみたい。

RootManifestでは異なるパーティション仕様が混在する可能性があるため、マニフェストとパーティションは可能な限り結びつけたくないらしい。
ほとんどのケースでは、あるフィールドの lower/upper が等しい場合、実質的にパーティションをtupleを再構成できる(マニフェストに含めなくてもいい)が、文字列/バイナリ列がパーティションに使われた場合、値がtruncateされている可能性があるため微妙らしい。

そもそも、Partition Tupleが必要かは↓の記事がわかりやすかった。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?