Icebergのパーティション変更した場合のS3ディレクトリ構造の変化を確認する

# 確認したいこと
Iceberg は、パーティションを途中で変更することができます。

https://iceberg.apache.org/docs/latest/evolution/#partition-evolution

物理データをS3に格納した場合、パーティションを変更したら物理的なS3のディレクトリ構造はどう変化するのかを確認してみました。

# 結論
変更前はdt_day（日付）でパーティションを切って、変更後はidでパーティションを切った場合は以下のようになりました。

- 変更前
```bash
myfolder
└── data
    ├── 2pM-Cg
    │   └── dt_day=2024-08-01
    ├── puBT4w
    │   └── dt_day=2024-08-02
    └── Mte4cw
        └── dt_day=2024-08-03
```

- 変更後
```bash
myfolder
└── data
    ├── 2pM-Cg
    │   └── dt_day=2024-08-01
    ├── puBT4w
    │   └── dt_day=2024-08-02
    ├── Mte4cw
    │   └── dt_day=2024-08-03
    ├── fs5Tg
    │   └── id=4
    └── gH2-w
        └── id=5
```

dataフォルダの下にランダム英数字のフォルダがあり、その下にパーティションが存在します。そのパーティションが、途中から変わりました。

# やってみる

## AthenaでIcebergテーブルを作成する
以下を参考に、AthenaでCREATE文を実行しました。

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/querying-iceberg-creating-tables.html

```SQL
CREATE TABLE default.iceberg_test_tbl (id bigint, data string, dt timestamp)
  PARTITIONED BY (day(dt))
  LOCATION 's3://my-bucket/tbl1-test/'
  TBLPROPERTIES ( 'table_type' = 'ICEBERG' );
```

パーティションもうまく設定されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/d43a1abc-fd03-4654-b1ac-083258b862b2.png)

## Athenaでレコード追加する
以下の5件を追加しました。
ちなみに、1行ずつ選択して実行していきました（一気に実行できないため）。

```SQL
INSERT INTO iceberg_test_tbl VALUES (1,'test',TIMESTAMP '2024-08-01 01:12:13');
INSERT INTO iceberg_test_tbl VALUES (2,'test',TIMESTAMP '2024-08-01 02:12:13');
INSERT INTO iceberg_test_tbl VALUES (3,'test',TIMESTAMP '2024-08-02 03:12:13');
INSERT INTO iceberg_test_tbl VALUES (4,'test',TIMESTAMP '2024-08-02 04:12:13');
INSERT INTO iceberg_test_tbl VALUES (5,'test',TIMESTAMP '2024-08-03 05:12:13');
```

:::note info
タイムスタンプは、単純にシングルクォートで囲っただけだと文字列として認識されてしまい失敗します。
[Athenaのデータ型の例](https://docs.aws.amazon.com/ja_jp/athena/latest/ug/data-types.html#data-types-examples)を参考に、上記のように指定しました。
:::

SELECT文を実行し、上手く追加されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/aaf05f7b-99a0-e79a-a948-6faa8e8de55a.png)

## S3のディレクトリを確認する
以下のように、5つのランダム英数字のフォルダが作成されています。5件レコード追加したからでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/b5a0e6a6-e79e-d795-bf57-849ccf95940f.png)

1つ中身を見てみると、このようにdt_dayと日付でパーティションが切られています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/cd8a4e31-2fe1-9b68-35fe-29c42647b047.png)

## Glueでパーティションを変更する
Athenaではパーティション変更するDDLはサポートしていないため（2024年8月16日時点）、Glueで実行していきます。

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/querying-iceberg-additional-operations.html

Glueで以下のジョブ（Glueのバージョンは4）を実行しました。SQL文はドキュメントの以下のあたりを参考にしました。

https://web.archive.org/web/20221207033838/https://iceberg.apache.org/docs/1.0.0/spark-ddl/#alter-table-sql-extensions

```python
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

## @params: [JOB_NAME]
args = getResolvedOptions(sys.argv, ['JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# パーティション削除
spark.sql("ALTER TABLE glue_catalog.default.iceberg_test_tbl DROP PARTITION FIELD dt_day")

# パーティション追加
spark.sql("ALTER TABLE glue_catalog.default.iceberg_test_tbl ADD PARTITION FIELD id")

job.commit()
```

GlueでIcebergにクエリを実行する際は、以下に記載のあるようにジョブパラメータを設定するのを忘れないようにしましょう。

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-format-iceberg.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/4e4bfe4e-a9bd-6800-4d3b-24c682801c8e.png)

:::note info
`--conf`のValueは、改行も入るかなり長い値です。
:::

Athenaでパーティションを確認すると、変更されていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/fc9889ea-6ae6-4b9f-50af-0cdf90fd1ded.png)

## Athenaでレコード追加する（変更後）
追加で2件のレコードを追加しました。

```SQL
INSERT INTO iceberg_test_tbl VALUES (11,'test',TIMESTAMP '2024-08-04 06:12:13');
INSERT INTO iceberg_test_tbl VALUES (12,'test',TIMESTAMP '2024-08-05 07:12:13');
```

SELECT文を実行すると、先ほどの5行と今回の2行で7件のレコードが格納されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/8897eb6f-f54a-c4fb-228e-6831b6eedd51.png)

## S3のディレクトリを確認する（変更後）
再度S3を確認すると、ランダム英数字のフォルダが2つ増えて7個になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/9060dc1b-f505-ad2c-dcb9-fe7faf08db14.png)

その中で前はなかったフォルダの中身を見てみると、変更後のパーティションである`id`でパーティションが切られていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/916d9375-76d0-c129-986c-7b3da0f589b7.png)

このように、パーティション変更してからは物理的にディレクトリ構成が変わるんですね。

# 注意点
直接関係はないですが、以下のバージョンの差異があることに気を付けてください。
- Athenaで利用しているIcebergのバージョン
- Glueで利用しているIcebergのバージョン
- 最新のIcebergのバージョン

:::note warn
**2024年8月16日時点**の対応バージョンを以下に記載します。実際に利用する際は適宜最新のドキュメントをご確認ください。
:::

### Athena
Apache Iceberg バージョン 1.4.2 を使用しています。

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/querying-iceberg.html

### Glue
Glue v4 は Apache Iceberg バージョン 1.0.0 を使用しています。
Glue v3 は Apache Iceberg バージョン 0.13.1 を使用しています。

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-format-iceberg.html

### Iceberg
最新は Apache Iceberg バージョン 1.6.0 です。

https://iceberg.apache.org/releases/