Snowflake新機能のIceberg Tableを構成する各種ファイルの挙動を確認してみた

こんにちは。日本ビジネスシステムズ株式会社の岩間です。

最近、Snowflake学習の一環で、Iceberg Tableを構成するレイヤーであるmetadataレイヤーの各種構成ファイルの挙動を確認しましたので、その内容をこちらで共有させていただきます。

Snowflakeの新機能として追加されたIceberg Tableは注目度が高い一方で、少し内容が複雑なため、理解に苦しんでいる方もいらっしゃるのではないかと思います。少しでもそういった方々のお役に立てれば幸いです。

本記事のスコープ

本記事では「Iceberg Tableの概要はつかめている人」をターゲットとしていますので、Iceberg Tableがそもそもどういったものなのかという説明は割愛しております。

Icberg Tableの概要については、本当に分かりやすく解説されていらっしゃる方の記事がいくつもあるので、そちらをご参考ください!

また、本記事ではIceberg Tableを構成するレイヤーの内、metadataレイヤーの以下構成ファイル群についてのみ調査しております。

構成ファイル名 概要
metadata file テーブルの状態を保持しているファイル。テーブルに何かしらの変更があった際に新しいmetadata fileが作成され、古いmetadata fileと入れ替えられます。
manifest list 特定の時点でのsnapshotを保持しているファイル。snapshotは複数のmanifest fileから構成されており、それらmanifest fileのリストとmanifest file自身のmetadataを格納している。snapshot1つにつきmanifest listは1つ。※ひとまずは「manifest fileの一覧」とだけ理解いただければと思います!
manifest file 実データであるdata fileのリストとそのdata fileのmetadata(data fileのファイル名など)を格納している。

今回使用するIceberg Tableについて

本記事では、Snowflake社が用意しているクイックスタートシリーズで作成したIceberg Tableを使用しています。

quickstarts.snowflake.com

以下にテーブルの概要をまとめておきます。

データの内容

このシリーズで使用するデータは、Snowflake社のクイックスタートシリーズでおなじみの架空のキッチンカーブランド"Tasty Bytes"によって収集された、各レストランのレビューデータです。

オーダーID、キッチンカーID、注文年月、レビューなどのデータが含まれています。

Iceberg Tableの内容

このクイックスタートシリーズではIceberg TableとExternal Tableの比較もかねているため、csv形式のレビューデータS3にアップロードして、それらを基にExternal Tableを作成するところから始まります。

そして、External TableのデータをSELECTしてIceberg TableにINSERTして、Iceberg Tableを作成しています。

そのため、後続で紹介するIceberg Table作成時のクエリではFROM句にExternal Tableを記載しています。

※Iceberg Table作成にExternal Tableは必須ではありません。

実際に操作して構成ファイルの挙動を確認してみた

テーブル定義作成時

クイックスタートシリーズの中で、以下のクエリでテーブル定義を作成しました。

CREATE OR REPLACE ICEBERG TABLE tasty_bytes_db.raw.icb_truck_reviews
        (
        source_name VARCHAR,
        quarter VARCHAR,
        order_id BIGINT,
        truck_id INT,
        review VARCHAR,
        language VARCHAR
        )
        CATALOG = 'SNOWFLAKE'
        EXTERNAL_VOLUME = 'vol_tastybytes_truckreviews'
        BASE_LOCATION = 'iceberg_table/';

作成後にS3を確認してみると、やはりテーブル定義を作成しただけでデータを投入していないことから、metadataディレクトリのみが作成されていました。

metadataディレクトリの中にはmetadata fileが1つだけ作成されていました。

このmetadata fileの中身を確認してみると、テーブルの状態に関する様々な情報を確認できました。

  • location:metadataとデータが格納されるS3バケット
  • last-updated-ms:最後に更新のあったunixタイム(ミリ秒)
  • snapshots:スナップショットに関する情報 ※データがないため空白

データの初期投入時

次に、クイックスタートシリーズの手順の中で作成したIceberg Tableに、以下のクエリでExternal Tableのデータを投入しました。 ※レコード数:83345行

INSERT INTO tasty_bytes_db.raw.icb_truck_reviews
(
source_name, quarter, order_id, truck_id, review, language
)
SELECT source as source_name,
    quarter,
    order_id,
    truck_id,
    review,
    language
FROM tasty_bytes_db.raw.ext_survey_data;

その後、S3を確認してみると、新しくdataディレクトリが作成されていました。

dataディレクトリの中を確認すると、data fileがparquet形式で保存されているのが分かります。

metadataディレクトリの中を確認すると、テーブル定義作成時とは違い、複数の構成ファイルが作成されているのが分かります。

metadata fileの中身を確認

先ほどテーブル定義を作成したときとは違い、snapshotに関する情報が付け足されていることが確認できました。

manifest listの中身を確認

「manifest listの一覧」なので、このsnapshotを構成するmanifest fileのパスが表示されており、"added_rows_count"では今回追加した83345行という数字が確認できました。

※manifest listはavro形式であるため、コンバーターを使用してCSV形式にして中身を確認しています。

manifest fileの中身を確認

表示の都合上省略していますが、data fileのリストおよびそれらに関するmetadata(data fileのパスなど)が確認できました。

※manifesはavro形式であるため、コンバーターを使用してCSV形式にして中身を確認しています。

追加でInsertを実行

次に、作成したIceberg Tableに対して以下クエリを実行して、最初に追加したデータのtruck_idを2倍にしただけのものをそのまま追加してみました。※追加レコード数:83345行

INSERT INTO tasty_bytes_db.raw.icb_truck_reviews
(
source_name, quarter, order_id, truck_id, review, language
)
SELECT source as source_name,
    quarter,
    order_id,
    truck_id * 2 as truck_id,
    review,
    language
FROM tasty_bytes_db.raw.ext_survey_data;

その後、S3を確認してみると、metadataディレクトリには最初のデータ投入時と同じように新しく構成ファイルが作成されていました。

また、dataディレクトリの中にも同様に新しいdata fileが作成されていました。

ここでも同じく、metadataディレクトリに新規作成されたファイル群の中身を確認していきます。

metadata fileの中身を確認

データ投入時と同じように、snapshotの情報などが確認できました。

manifest listの中身を確認

今回のデータ投入では83345行のテーブルに83345行を新規に追加しているので、合計166690行となります。

しかし、以下の赤枠で囲っている箇所を見ると、2行目の"deleted_rows_count"が83345行で、1行目の"added_rows_count"が166690となっています。

ここだけを見るとまるで元のデータをすべて削除してから、元のデータ+新規追加分を一気に追加しているように見えました。実際に実行したクエリは元のデータを削除するわけではなく単に新しくレコードを追加しているだけなので、この点に疑問を持ち、この値について追加で調査してみました。

Apache Icebergの公式ドキュメントを確認すると以下のことが分かりました。

  • deleted_rows_countは、stateがDELETEDな行の数
    • stateがDELETEDなだけで実際にデータは消えていない(参考リンク
    • 実際にdataディレクトリを見てもdata fileは消えていない
  • Iceberg Tableで新規に行が追加される場合は、既存のmanifest fileを書き換えるのではなく新規にmanifest fileを作成することで処理を早くしている(参考リンク
  • テーブルスキャンが実行される際に、manifest fileの中でstateがDELETEDになっている行はスキャンがスキップされるため処理が早くなる(参考リンク

まとめると以下の通りです。

  • deleted_rows_countは実際にデータが削除された行数のカウントではない
  • manifest fileを書き換えるのではなく、manifest fileを2つ用意して一方でdeleted_rows_countに83345行を記載しているのは、そちらの方が処理が早いため
manifest fileの中身を確認

上記manifest listに記載のあるmanifest fileの中身もそれぞれ見てみようと思います。

【末尾が「TTFw」のmanifest file】※"added_rows_count"が166690の方のファイル

【末尾が「eRdg」のmanifest file】※"deleted_rows_count"が83345の方のファイル

赤枠の箇所を比べてみると、後者のファイルの方では、data fileに関するmetadataが全てnullになっているのが分かりました。

さいごに

今回の記事では、実際にIceberg Tableのmetadataレイヤーの各構成ファイルの挙動を見てみました。その結果各ファイルの役割や存在意義に対する理解がより一層深まったかと思います。

今後はdeleteやtime travel機能を使用した際のmetadata layerの挙動も確認しようと思っておりますので、その際もぜひご一読ください。

※我々JBSは今年2024年にサンフランシスコで開催されたSnowflakeの年次イベント「Data Cloud Summit 2024」に参加してきました。その際の現地レポート記事も投稿しておりますので、ぜひご確認ください。

執筆担当者プロフィール
岩間 義尚

岩間 義尚

2021年度新卒入社後、Hadoopを中心に複数のデータ基盤の開発/運用を経験。 現在はSnowflakeやAzureでのデータエンジニアリングをメインに担当しています。

担当記事一覧