🤖

オープンテーブルフォーマットとは

に公開

はじめに

オープンテーブルフォーマット なるものを知らなかったので整理しておこうと思います。3つの記事を読んでみました。それぞれの記事を読んで抜粋、翻訳した内容になっています。

  1. データレイクの新しいカタチ
    ざっくり雰囲気を掴めました。理解力がある人が読めばこれだけで問題なさそうです!
  2. オープンテーブルフォーマットを解き明かす:Delta-Lake-vs-Iceberg-vs-Hudi
    オープンテーブルフォーマットの比較の解説です。1つ目の記事で同じことが書かれている気がします。こっちのほうが記事としては新しいので新しい情報があるのかもしれません。
  3. オープンテーブルフォーマットを理解する
    Delta Lake が書いた記事で、私個人としてはこの記事が一番しっくり来ました。

データレイクの新しいカタチ

オープンテーブルフォーマット とは次世代のデータレイクの基盤となりうる技術だそうです。

オープンテーブルフォーマットでできるようになること

従来のデータレイクの技術的な課題やユースケースの要請に応えるための「データレイクに最適化されたテーブルフォーマット」のこと、で以下を実現可能にした

  • クエリプランニング
  • 実効性能の最適化
  • 効率的なUpdateやDelete
  • タイムトラベルクエリ
  • スキーマ変更への追従

オープンテーブルフォーマットの起こり

更にリンク先にはAWSを使った場合の具体例に加え、以下が整理されています。

技術的課題の詳細

  • 課題①レコードレベルの変更が非効率
  • 課題②同時書き込み、読込みの独立性を確保できない
  • 課題③テーブルを編集すると過去の断面が復元できない
  • 課題④テーブルを構成するファイルが増えるとテーブル操作が高コスト化する
  • 課題⑤スキーマ変更への追従が大変
  • 課題⑥効率よくクエリを実行するにはユーザがテーブルの物理構造を把握する必要がある

ユースケースの要請

  • ストリームデータの処理
  • Change data capture (CDC)
  • 個人情報保護法対応(データ削除及び削除時の参照)
  • データサイエンス(あるタイミングで実施した実験の再現)
  • ユースケースの要請

具体的なフォーマット

さいごに Data Lake Table Formatの種類 としてメジャーな3種類のフォーマットが整理されています。

  • Apache Hudi
  • Apache Iceberg
  • Delta Lake

読んでみたものの個人的にはまだぼんやりしています。

オープンテーブルフォーマットを解き明かす:Delta-Lake-vs-Iceberg-vs-Hudi

上記情報は少し古かったこともあるので、改めてより新しい以下の記事を読んでみます。

最新のデータレイクに最適なオープンテーブルフォーマットを理解し、選択するための必携ガイド

序章

データ量が爆発的に増加し、分析が意思決定にますます重要になる中で、データレイクはモダンなデータプラットフォームの中核として台頭してきました。しかし、データレイクは生データをそのまま扱う性質から、読み取りの不整合、ACID保証の欠如、ガバナンスの複雑化といった混乱を招くことがあります。

そこで登場するのがオープンテーブルフォーマットです。これにより、Amazon S3、Azure Blob Storage、HDFSといったオブジェクトストアのスケーラビリティを損なうことなく、ACIDトランザクション、スキーマ進化、タイムトラベルなど、データベースのような機能をデータレイクに追加できます。

もしオープンテーブルフォーマットの世界に初めて触れるなら、Delta Lake、Apache Iceberg、Apache Hudi の名前を目にしたことがあるはずです。では、どのフォーマットを選べばよいのでしょうか。

この記事では以下の点を解説します。

  • オープンテーブルフォーマットとは何か、そしてなぜ重要なのか
  • Delta Lake、Iceberg、Hudi の比較
  • アーキテクチャの違い
  • Netflix や Uber における実際の利用事例
  • 各フォーマットに最適なユースケース

読み終える頃には、自分のユースケースに合ったフォーマットを選べるようになるでしょう。

オープンテーブルフォーマットとは?

従来のデータレイクは、生のファイル(多くはParquet)を格納するだけで、構造やメタデータの追跡、トランザクション保証が欠けていました。オープンテーブルフォーマットは、この上にトランザクション性とクエリ可能なレイヤーを追加することで、この問題を解決します。

これにより、次のことが可能になります。

  • データレイクをデータベースのように扱える
  • 挿入、更新、削除を確実に実行できる
  • スキーマ変更やクエリ時のフィルタリングに対応
  • ストリーミング処理とバッチ処理を同時に実行できる

現在、この分野を牽引している主な3つのフォーマットは以下の通りです。

  • Delta Lake(Databricks製)
  • Apache Iceberg(Netflix発)
  • Apache Hudi(Uber開発)

アーキテクチャの違い

Delta Lake

  • _delta_log/ と呼ばれるトランザクションログを使用
  • Spark(特にDatabricks)との密な統合
  • Sparkを用いたバッチ処理およびストリーミング処理に最適

Apache Iceberg

  • メタデータはスナップショットおよびマニフェストファイルに保存
  • スケーラビリティとマルチエンジン互換性を重視した設計
  • パーティション進化や隠しパーティション(hidden partitioning)をサポート

Apache Hudi

  • Copy-On-Write(COW)テーブルと Merge-On-Read(MOR)テーブルをサポート
  • コミットのタイムラインを保持し、増分取り込み(incremental ingestion)を実現
  • 組み込みのインデックス、クリーンアップ、コンパクション機能を提供

実際のユースケース

Netflix における Apache Iceberg の活用

  • Spark、Presto、Flinkなど複数のエンジンでペタバイト規模の分析データを管理する必要があった
  • 単一のコンピュートフレームワークに依存せず、スキーマ進化の柔軟性、スナップショット分離、ファイルリストによるボトルネックを回避しつつメタデータをスケール可能
  • 推薦エンジンやデータサイエンスパイプラインなど、多様なワークロードを支える基盤として利用

Uber における Apache Hudi の活用

  • リアルタイム取り込み基盤を構築するためにHudiを開発
  • 毎日数百万件の配車が発生するため、高速な取り込み、配車ステータス変更などのイベント更新、迅速な分析処理が必要だった
  • アップサート、増分読み取り、Merge-on-Readテーブルのサポートが要件に適合

コード例

Delta Lake (PySpark)

from delta.tables import DeltaTable
from pyspark.sql import SparkSession
spark = SparkSession.builder \
    .appName("DeltaExample") \
    .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
    .config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
    .getOrCreate()
# Write to Delta table
data.write.format("delta").mode("overwrite").save("/tmp/delta-table")
# Read Delta table
df = spark.read.format("delta").load("/tmp/delta-table")

Apache Iceberg (Spark SQL)

-- Enable Iceberg
SET spark.sql.catalog.my_catalog = org.apache.iceberg.spark.SparkCatalog;
SET spark.sql.catalog.my_catalog.type = hadoop;
SET spark.sql.catalog.my_catalog.warehouse = /tmp/iceberg-warehouse;
-- Create Iceberg table
CREATE TABLE my_catalog.db.table1 (
  id bigint,
  data string,
  ts timestamp
) USING iceberg;
-- Insert data
INSERT INTO my_catalog.db.table1 VALUES (1, 'A', current_timestamp());

Apache Hudi (Spark DataSource API)

hudi_options = {
  'hoodie.table.name': 'hudi_trips_cow',
  'hoodie.datasource.write.recordkey.field': 'trip_id',
  'hoodie.datasource.write.precombine.field': 'ts',
  'hoodie.datasource.write.table.name': 'hudi_trips_cow',
  'hoodie.datasource.write.operation': 'upsert',
  'hoodie.datasource.write.storage.type': 'COPY_ON_WRITE',
  'hoodie.datasource.hive_sync.enable': 'true',
  'hoodie.datasource.hive_sync.database': 'default',
  'hoodie.datasource.hive_sync.table': 'hudi_trips_cow',
  'hoodie.datasource.hive_sync.partition_fields': 'region'
}
df.write.format("hudi") \
    .options(**hudi_options) \
    .mode("overwrite") \
    .save("s3://your-bucket/hudi-trips")

いつどれを使うか

Delta Lake

  • Spark(特にDatabricks)を主に利用している場合
  • ACID保証と簡単なアップサートが必要な場合
  • 柔軟性よりもシンプルなアーキテクチャを優先する場合

Apache Iceberg

  • マルチエンジンかつベンダーロックインのないソリューションが必要な場合
  • データのパーティションやスキーマが時間とともに変化する場合
  • ペタバイト規模で運用している場合

Apache Hudi

  • 頻繁な更新・削除を伴うリアルタイム取り込みが必要な場合
  • インクリメンタルなパイプラインを構築したい場合
  • インデックス、クリーンアップ、コンパクションの組み込み機能が重要な場合

まとめ

オープンテーブルフォーマットは、生のファイルベースストレージとフル機能のデータベースとのギャップを埋める存在です。
それぞれのフォーマットには固有の強みがあります。

  • Delta Lake: Sparkネイティブでシンプル、完全なACID対応
  • Apache Iceberg: エンジン非依存、スケーラブルなメタデータ、豊富なスキーマ進化機能
  • Apache Hudi: リアルタイムかつインクリメンタルな取り込み、インデックスとコンパクション対応
    万能な選択肢は存在しません。適切なフォーマットは、利用する計算エンジン、データ取り込みパターン、クエリワークロードによって異なります。

知識と事例を踏まえ、実際に試してあなたのデータレイクに最適なものを見つけてください。

オープンテーブルフォーマットを理解する

上記読んで具体例が見えてきたものの、いまいちしっくり来ていないので、もういっちょ読んでみます。Delta Lakeの記事です。

この記事は、オープンテーブルフォーマットとは何か、そして表形式データの保存においてそれが優れた選択肢である理由を解説しています。

  • 従来のデータ保存手法と比較した際の利点
  • オープンテーブルフォーマットの種類
  • Delta Lake Uniform、XTable、Unity Catalog などによるフォーマット間の相互運用性

オープンテーブルフォーマットは CSV や Parquet のような単なるファイルフォーマットより効率的かつ信頼性が高く、ACID トランザクション、高度なデータスキッピング、タイムトラベルなどの機能を備えています。代表例として Delta Lake があり、他にも Apache Iceberg や Apache Hudi があります。

異なるオープンテーブルフォーマット間には差異がありますが、相互運用性を支える技術の登場により、その差は次第に重要性を失いつつあります。
Delta Lake UniForm や Unity Catalog といったプロジェクトが、オープンテーブルフォーマット間のギャップを埋めています。
これらのプロジェクトについては記事の最後で解説します。

まずは、オープンテーブルフォーマットとは何か、そしてそれがなぜ素晴らしいのかを見ていきましょう。

オープンテーブルフォーマットって何?

オープンテーブルフォーマットは、Parquet や ORC のような既存のファイルフォーマットの上に構築された、表形式データを保存するためのオープンソース技術です。
オープンテーブルフォーマットでは、表形式データをファイルに保存し、そのデータや操作に関するメタデータを別のファイルまたはディレクトリに保存します。
このメタデータによって、高速なクエリ処理、信頼性の高いトランザクション、データ破損のリスク低減といった多くの優れた機能が可能になります。

代表的なオープンテーブルフォーマットは、Delta LakeApache HudiApache Iceberg の3つです。

なぜオープンテーブルフォーマットを使うの?

オープンテーブルフォーマットは、従来のデータレイクにおけるパフォーマンスや信頼性の問題を解決します。
表形式データと共にメタデータを保存することで、次のような優れた機能を提供します。

  1. 信頼性の高い ACID トランザクション
  2. 高度なデータスキッピング
  3. タイムトラベル
  4. スキーマの強制および進化
  5. 完全な CRUD 操作

オープンテーブルフォーマット:信頼性の高い ACID トランザクション

オープンテーブルフォーマットは、データレイクのエコシステムに ACID 保証をもたらすために開発されました。
ACID トランザクションにより、データ書き込みの信頼性が向上し、操作によってテーブルが破損することを防ぎます。
ここでいう「トランザクション」とは、テーブルの状態を変更するあらゆる書き込み操作を指します。

ACID トランザクションを使用することで、以下を確実に回避できます。

  • 下流のクエリを壊す原因となる、失敗した部分的な書き込み
  • 偶発的なデータ破損
  • 同時実行プロセスやデータバージョンの競合
  • 意図しないデータ損失

詳細は「Delta Lake vs Data Lake」の記事をご覧ください。

以下のセクションで、それぞれの機能を詳しく見ていきます。

オープンテーブルフォーマット:高度なデータスキッピング

オープンテーブルフォーマットは、Parquet や CSV のようなファイルフォーマットよりも高度なデータスキッピング機能を提供します。
メタデータを中央のメタデータディレクトリに保存することで、クエリエンジンは選択的なクエリに必要なデータを容易に見つけることができます。

Delta Lake は、次の方法で高度なデータスキッピングをサポートしています。

  1. 中央集約されたトランザクションログでの効率的なメタデータ保存
  2. Z-orderingLiquid Clustering による最適化されたデータレイアウト

これらの戦略により、クエリの実行速度は大幅に向上します。

詳細は Data Skipping ガイド を参照してください。

オープンテーブルフォーマット:タイムトラベル

オープンテーブルフォーマットはタイムトラベルをサポートしています。これは、データセットの過去バージョンを簡単に確認したり、必要に応じて元に戻すことができることを意味します。

Delta Lake はトランザクションログを通じてデータのバージョン管理を行います。
データに加えたすべての変更はこのログに記録されるため、過去のバージョンを簡単に参照し、誤って行った変更を修正することが可能です。

Delta テーブルの特定バージョンを読み込む例:

spark.read.format("delta").option("versionAsOf", version).load("path/to/delta")

詳細は Delta Lake Time Travel の記事をご覧ください。

オープンテーブルフォーマット:スキーマの強制と進化

データの一貫性を確保し、破損を防ぐためには、新しいデータが既存のスキーマと一致していることを確認する必要があります。これをスキーマ強制(schema enforcement)と呼びます。

Parquet や CSV などの多くの標準ファイル形式は、デフォルトではスキーマ強制をサポートしていません。つまり、例えば既存の Parquet データレイクに異なるスキーマのデータを書き込むことが容易にできてしまいます。これは、データを読み取ろうとした際に下流で問題を引き起こします。

オープンテーブルフォーマットは、デフォルトでスキーマ強制機能を備えています。これにより、誤ってデータを破損させることを防ぎます。

では、Delta Lake でこれを実際に見てみましょう。

first_nameage の2つのカラムを持つ Delta テーブルを作成します。

df = spark.createDataFrame([("bob", 47), ("li", 23), ("leonard", 51)]).toDF(
    "first_name", "age"
)

df.write.format("delta").save("tmp/fun_people")

では、このテーブルに異なるスキーマを持つデータを書き込んでみましょう。

df = spark.createDataFrame([("frank", 68, "usa"), ("jordana", 26, "brasil")]).toDF(
    "first_name", "age", "country"
)

df.write.format("delta").mode("append").save("tmp/fun_people")

この操作は AnalysisException エラーを引き起こします。

Delta Lake は、デフォルトではスキーマが一致しないデータの追加を許可しません。意図的にスキーマを更新したい場合は、mergeSchema オプションを使用できます。

df.write.option("mergeSchema", "true").mode("append").format("delta").save(
    "tmp/fun_people"
)

詳細については、「Delta Lake Schema Enforcement」および「Delta Lake Schema Evolution」の記事をご覧ください。

オープンテーブルフォーマット: 完全なCRUD操作

通常のParquetファイルは不変(immutable)です。Parquetファイルを変更する唯一の方法は、ファイル全体を完全に上書きすることです。 これは意図された仕様であり、データを誤って破損させることを防ぎます。

Delta Lakeのようなオープンテーブルフォーマットは、通常のParquetファイルよりも高い信頼性と柔軟性を提供します。 オープンテーブルフォーマットを使えば、データの一部に対してCRUD(作成・読み取り・更新・削除)操作を実行できます。

例えば、Delta LakeのreplaceWhere操作を使うことで、テーブル内の特定の行だけを選択的に上書きすることが可能です。

(
    df.write.format("delta")
    .option("replaceWhere", "number > 2")
    .mode("overwrite")
    .save("tmp/my_data")
)

オープンテーブルフォーマットでは、このような部分的なデータ更新を「論理操作」として処理します。
削除や上書き操作は、トランザクションログ内のマーカーを新しい行や列を指すように変更するだけです。 実際のデータそのものは変更されません。 この方法により、高コストな全体書き換えを行わずに、安全に部分的なデータ変更を行うことができます。

異なるオープンテーブルフォーマットを一緒に使うことはできますか?

はい、異なるオープンテーブルフォーマットを一緒に使うことは可能ですが、慎重な計画が必要です。
Delta Lake、Apache Iceberg、Apache Hudi のようなオープンテーブルフォーマットは、それぞれ独立してデータセットを管理するように設計されています。各フォーマットは独自のメタデータ構造、トランザクション管理、API を持っており、このことが相互運用性を難しくしています。

Delta Lake UniformApache XTable のようなプロジェクトは、オープンテーブルフォーマット間のワークフローを統一する取り組みを進めています。たとえば、ETL ワークロードには Delta Lake を使用し、その後 UniForm を使って下流の BI や分析システムで Iceberg テーブルとしてデータを読み取ることができます。

Unity Catalog も、オープンテーブルフォーマットの相互運用性を向上させるプロジェクトの一つです。Unity Catalog を使えば、Delta Lake と Iceberg の両方のフォーマットで表形式データを保存・管理・アクセスできます。

詳細は「Unifying Open Table Formats」の記事を参照してください。

オープンテーブルフォーマットを Parquet のようなファイルフォーマットに変換できますか?

はい。ほとんどの場合、オープンテーブルフォーマット(例:Delta Lake)で保存されているテーブルを、その基盤となるファイルフォーマット(例:Parquet)に変換できます。

例えば、Delta テーブルを Hive スタイルのパーティションを持つ Parquet データレイクに変換するには、以下を行うだけです。

  1. 古いファイルを Vacuum で削除する
  2. トランザクションログディレクトリを削除する

いつオープンテーブルフォーマットを使えばいいの?

オープンテーブルフォーマットは、ほぼ常に Parquet、CSV、JSON といったファイルフォーマットのみのデータレイクよりも高速で、安全で、開発者に優しいです。 Delta Lake のようなオープンテーブルフォーマットは、次の理由から優れた選択肢となり得ます。

  • トランザクションとスキーマの強制をサポートしており、テーブルを破損させる可能性が大幅に低くなる
  • ファイルのメタデータをトランザクションログに抽象化し、高度なクラスタリングやデータスキッピングをサポートすることで、クエリを高速に実行できる
  • 列の削除、列名の変更、行の削除、DML 操作などの一般的なデータ操作を容易に行える

もし本番環境で重要な表形式データのワークフローを運用しているなら、オープンテーブルフォーマットはほぼ間違いなく最良の選択肢となるでしょう。

さいごに

今日は オープンデータフォーマット について学んでみました!

昔は色々自分で考えてやっていたところに標準規格が出てだいぶ楽になってきていることがわかりました。

更には オーブンテーブルフォーマット自体も相互運用が進んでいることがわかりました!ということはどれを選んでも大きな問題はなくなるので、開発者としては悩みが少なりますね。

異なるオープンテーブルフォーマット間には差異がありますが、相互運用性を支える技術の登場により、その差は次第に重要性を失いつつあります。
Delta Lake UniForm や Unity Catalog といったプロジェクトが、オープンテーブルフォーマット間のギャップを埋めています。

次は「Unifying Open Table Formats」を読んで相互運用について理解を深めたいと考えています。

Discussion