【AWS Athena】エラー HIVE_BAD_DATA: Field label's type {A} in parquet is incompatible with type {B} defined in table schema でハマった話

私がAWS AthenaおよびAWS Glueでメタデータの取り扱いでハマった話を共有いたします。


# ハマった経緯

1. parquetのデータをS3に配置する
2. Glueのテーブルを作成する
3. AthenaでSELECT文を実行するため、load partition()を実行しパーティションを読み込む
4. AthenaでSELECT文を実行する → parquet内でのデータ型の定義とGlueテーブルのテーブル定義に齟齬があるためエラーと表示される
5. テーブル定義を誤っていたことに気づきGlueのテーブル情報を修正する
6. AthenaでSELECT文を実行する → なぜかparquet内でのデータ型の定義とGlueテーブルのテーブル定義に齟齬があるためエラーと表示される(困惑)



# ハマった状況を再現

そのとき、ハマった状況を再現していきます。
まず、S3に配置するparquetをpysparkを使って作成する。

```python
from pyspark.sql.types import StructType
from pyspark.sql.types import StructField
from pyspark.sql.types import StringType
from pyspark.sql.types import IntegerType
rdd = sc.parallelize([
	('apple', 120),
	('banana', 220),
	('tomato', 320),
	('chicken', 300),
	])
schema = StructType([
	StructField('label', StringType(), False),
	StructField('value', IntegerType(), False),
	])
df = spark.createDataFrame(rdd, schema)
df.repartition(1).write.parquet('./output/')
```


dfの中身はこのようになっております。
labelのカラムがstring型、valueのカラムがint型です。
![スキーマ情報20200419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/4a507d59-928e-1a73-9e5c-ea2d98a5d5f1.png)


これをS3に配置します。今回は s3://inu-is-dog/2020-04-19-qiita/id=123/part-00000.snappy.parquet へ配置いたしました。
id=123がパーティションとなるのがミソです。

![s3path20200419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/86f733a0-e26a-e131-6024-529c18f054c6.png)



次にGlueでテーブルを手動で作成いたします。

- データベース名：sampledb
- テーブル名：table_20200419
- データストア：s3://inu-is-dog/2020-04-19-qiita/
- データ形式：Parquet
- スキーマ:
  - id(パーティションキー) [string]
  - label [int]
  - value [int]

あえて、スキーマのlabelのデータ型はstring型ではなく、int型(誤り)としています。
![テーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/b3d90b4b-3550-cc07-e583-3bd005f3ad71.png)


次にAthenaの画面に遷移します。
今回はidのパーティションを持つテーブルを作成したため、SELECT文を実行する前にid=123のパーティションを登録する。

```sql
ALTER TABLE sampledb.table_20200419 ADD PARTITION (id = '123');
```

![クエリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/798cbd64-0203-b6c8-fec4-c7169d6f5872.png)


それでは、SELECT文を実行してみましょう。

```sql
SELECT * 
FROM sampledb.table_20200419;
```

![エラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/be379900-5881-9b31-b37d-394ded34e6d4.png)


"HIVE_BAD_DATA: Field label's type BINARY in parquet is incompatible with type int defined in table schema"とエラーが表示されました。

Glueのテーブル登録でlabelのデータ型を誤って登録していたことが原因でしょう。



...ということで、table_20200419のスキーマの編集を行いました。

![テーブル2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/8d6f52d0-aa3f-9af2-bab3-05dc6edcdd23.png)


これで先ほどのSELECT文は通るはず....

![aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/575dd254-13d9-aca0-2593-f6403d3fed0a.png)


ダメでした.... 同じエラーメッセージです。(困惑)

Athenaの画面の左側のテーブル情報を見てもわかるのですがlabelのカラムは正常にstring型に更新されております。
それなら、なぜまた同じエラーメッセージなのか？？


# 原因

Glueのテーブル table_20200419へ画面を遷移させ、[パーティションの表示] → [id=123のプロパティの表示]をさせてみましょう。
![プロパティ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/86e632d7-6845-6506-d7f9-3dd5f24e43c5.png)
![プロパティ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/c0be3677-ec3d-69ef-64a6-48bf5f0e0b43.png)


id=123のパーティションではlabelはint型で扱うように設定されていることがわかります。

**パーティションごとのメタデータはそのパーティションを読み込んだ際のテーブル情報が登録されており、大元のテーブルの変更は反映されていない**ということになります。



# 対処法

この原因を踏まえて、大元のテーブルのカラム情報が変更された際には今まで読み込んでいたパーティションのメタデータも更新する必要があることがわかりました。

パーティションをDROPした後、改めてパーティションを読み込む対応方法を共有いたします。

```sql
ALTER TABLE sampledb.table_20200419 DROP PARTITION (id = '123');
```

```sql
ALTER TABLE sampledb.table_20200419 ADD PARTITION (id = '123');
```

これで無事、SELECT文が通るようになりました。
![サクセス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451269/83e6adbf-9ff7-7d6a-444d-4a860c055922.png)


この記事がみなさまの開発や分析の一助となれば幸いです。