Amazon S3 Tables でタイムトラベルクエリを試してみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは!アノテーション AWS テクニカルサポートチームの大高です。
先日、Amazon S3 Tables のテーブル作成と簡単なクエリを試してみました。
通常のクエリは問題なさそうでしたが、今回は Apache Iceberg テーブルの特徴である「タイムトラベルクエリ」を試してみたいと思います。
Amazon S3 Tables の「タイムトラベルクエリ」とは
Amazon S3 Tables は、Apache Iceberg サポートが組み込まれています。
この Apache Iceberg テーブルでは、S3 オブジェクトのバージョン管理されたマニフェストを維持しており、以前のバージョンのマニフェストを、タイムトラベルおよびバージョントラベルのクエリに使用できます。
つまりは、テーブルの過去のバージョンの状態に対してクエリができる、ということですね。
やってみた
今回は、下記のドキュメントを参照しながら、実際にタイムトラベルクエリを試してみます。
テーブルの履歴を確認する
タイムトラベルクエリでは、テーブルの特定の日時を指定する必要があります。
そのため、まずは Athena で以下のクエリを実行して、テーブルの履歴を確認してみます。
SELECT * FROM "sample_table$history" limit 10;
| # | made_current_at | snapshot_id | parent_id | is_current_ancestor |
|---|---|---|---|---|
| 1 | 2025-10-10 09:35:46.194 UTC | 4900786887601180495 | true | |
| 2 | 2025-10-10 09:35:54.781 UTC | 5469666753384997262 | 4900786887601180495 | true |
| 3 | 2025-10-10 09:36:03.297 UTC | 7919870596757976173 | 5469666753384997262 | true |
これは、3 件のレコードを 1 件ずつ INSERT した際のテーブル履歴となっています。
今回は、この中で一番古い 1 件だけレコードを入れた際の日時 2025-10-10 09:35:46.194 UTC を使ってみます。
タイムトラベルクエリを実行してみる
それでは、以下のクエリを実行してみます。
SELECT * FROM "sample_table" FOR TIMESTAMP AS OF TIMESTAMP '2025-10-10 09:35:46.194 UTC';
| # | id | name | value |
|---|---|---|---|
| 1 | 1 | name1 | 1 |
想定どおり、当時の 1 件だけレコードを入れたテーブルから SELECT ができました!
(おまけ) CloudShell に導入した Spark Shell からテーブルロールバックを試してみた
タイムトラベルクエリで取得した過去の状態へのテーブルロールバックも試してみました。
CALL s3tablesbucket.system.rollback_to_snapshot('sample_namespace.sample_table', 4900786887601180495');
しかし、Athena では以下のエラーが発生してプロシージャの CALL はできませんでした。
line 1:1: mismatched input 'CALL' expecting {'(', 'SELECT', 'FROM', 'ADD', 'DESC', 'WITH', 'VALUES', 'CREATE', 'TABLE', 'INSERT', 'DELETE', 'DESCRIBE', 'EXPLAIN', 'SHOW', 'USE', 'DROP', 'ALTER', 'MAP', 'SET', 'RESET', 'START', 'COMMIT', 'ROLLBACK', 'REDUCE', 'REFRESH', 'CLEAR', 'CACHE', 'UNCACHE', 'DFS', 'TRUNCATE', 'ANALYZE', 'LIST', 'REVOKE', 'GRANT', 'LOCK', 'UNLOCK', 'MSCK', 'EXPORT', 'IMPORT', 'LOAD'}
以下に記載のあるとおり、Apache Spark 環境が必要なようです。
注: Athena クエリエディターではなく、AWS Glue や Amazon EMR などの Apache Spark 環境でテーブルをロールバックする必要があります。
以下の記事を参考に、CloudShell で Spark Shell が使えるようにしてみます。
- Java の確認
CloudShell では標準で Java が利用できるはずなので、確認します。
$ java -version
openjdk version "21.0.8" 2025-07-15 LTS
OpenJDK Runtime Environment Corretto-21.0.8.9.1 (build 21.0.8+9-LTS)
OpenJDK 64-Bit Server VM Corretto-21.0.8.9.1 (build 21.0.8+9-LTS, mixed mode, sharing)
問題なく、Amazon Corretto 21 が導入済みですね。
- Apache Spark のダウンロードとインストール
以下のとおり、ダウンロードとインストールを行います。なお、ダウンロードするバージョンは 3.5.7 とします。
$ cd /tmp
$ wget https://dlcdn.apache.org/spark/spark-3.5.7/spark-3.5.7-bin-hadoop3.tgz
$ tar -xzf spark-3.5.7-bin-hadoop3.tgz
なお、最初はホームディレクトリに展開しようとしましたが、ストレージ不足となってしまったため、一時ストレージである /tmp を利用しています。
- 環境変数の設定
インストールしたパスを環境変数に設定して反映させます。
$ echo 'export SPARK_HOME=/tmp/spark-3.5.7-bin-hadoop3' >> ~/.bashrc
$ echo 'export PATH=$PATH:$SPARK_HOME/bin' >> ~/.bashrc
$ source ~/.bashrc
- 動作確認
$ spark-shell --version
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/___/ .__/\_,_/_/ /_/\_\ version 3.5.7
/_/
Using Scala version 2.12.18, OpenJDK 64-Bit Server VM, 21.0.8
Branch HEAD
Compiled by user runner on 2025-09-17T20:37:30Z
Revision ed00d046951a7ecda6429accd3b9c5b2dc792b65
Url https://github.com/apache/spark
Type --help for more information.
これで、無事に spark-shell が利用できるようになりましたので、以下のドキュメントを参考に起動してみましょう。
--conf spark.sql.catalog.s3tablesbucket.warehouse= で指定する ARN は自分の S3 Tables のバケットに書き換えます。
また、 --packages には、org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.5.0 と software.amazon.awssdk:bundle:2.20.0 を追加で指定しています。
なお、ストレージ不足を防ぐため ivy のキャッシュも spark.jars.ivy=/tmp/.ivy2 として /tmp 配下を指定しています。
$ spark-shell \
--packages software.amazon.s3tables:s3-tables-catalog-for-iceberg-runtime:0.1.3,org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.5.0,software.amazon.awssdk:bundle:2.20.0 \
--conf spark.jars.ivy=/tmp/.ivy2 \
--conf spark.sql.catalog.s3tablesbucket=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.s3tablesbucket.catalog-impl=software.amazon.s3tables.iceberg.S3TablesCatalog \
--conf spark.sql.catalog.s3tablesbucket.warehouse=arn:aws:s3tables:ap-northeast-1:XXXXXXXXXXXX:bucket/ootaka-sample-s3-table-backet \
--conf spark.sql.defaultCatalog=s3tablesbucket \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
起動できたら、試しに namespace を確認します。
scala> spark.sql("SHOW NAMESPACES").show()
+----------------+
| namespace|
+----------------+
|sample_namespace|
+----------------+
想定どおり、表示されました。
では、本命のテーブルロールバックをしてみます。以下では 1 件のレコードが入っていた時点のスナップショット ID を指定しています。
spark.sql("CALL s3tablesbucket.system.rollback_to_snapshot('sample_namespace.sample_table', 7827017876549943173)").show()
+--------------------+-------------------+
|previous_snapshot_id|current_snapshot_id|
+--------------------+-------------------+
| 7511407681386237430|5982459232010435748|
+--------------------+-------------------+
この状態で下記のように SELECT してみましたが、なぜか 0 件になってしまいました。
scala> spark.sql("SELECT * FROM sample_namespace.sample_table").show()
+---+----+-----+
| id|name|value|
+---+----+-----+
+---+----+-----+
なお、タイムスタンプを利用した下記のプロシージャも利用しましたが同様でした。
spark.sql("CALL s3tablesbucket.system.rollback_to_timestamp('sample_namespace.sample_table', TIMESTAMP '2025-10-16 09:32:47.061')").show()
なんらかの設定不足が原因でメタデータの読み込みが失敗しているように思われましたが、現時点では明確な原因を掴むことができませんでした。
今後なにか分かったら追記したいと思います。
まとめ
以上、Amazon S3 Tables のタイムトラベルクエリを試してみました。
「誤ってレコードを DELETE してしまった」などの場合には、タイムトラベルクエリで Athena 上から簡単に過去データを参照できるので助かりそうですね。
どなたかのお役に立てば幸いです。それでは!
参考








