この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
先日、Amazon Athenaで以下のエラーに遭遇したので、原因と解決方法を記しておきます。
GENERIC_INTERNAL_ERROR: No partition found with values [20211031]
ちなみに2021年11月2日現在、上記に関する公式ドキュメントは見つかっておりません。
原因
エラーメッセージには「"20211031"の値のあるパーティションが見つかりません」という意です。Amazon AthenaでPartition Projectionを使用している時に表示されるエラーの模様で、Partition Projectionの設定の範囲外のパーティションに対してINSERTが実行されようとすると、「そのパーティションは存在しない」と怒られるわけです。
私の手元では、以下のようなDDLを設定していました。projection.yyyymmdd.range
で、日付パーティションの範囲を2018年3月1日
〜現在時刻
として定義しています。
CREATE EXTERNAL TABLE IF NOT EXISTS `cm-haruta`.`partition_error` (
`id` string COMMENT '',
`time` string COMMENT ''
)
PARTITIONED BY (
`date_created` string COMMENT '')
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
's3://cm-haruta/partition_error'
TBLPROPERTIES (
'has_encrypted_data' = 'false',
'projection.enabled' = 'true',
'projection.date_created.type' = 'date',
'projection.date_created.range' = '2018-03-01,NOW',
'projection.date_created.format' = 'yyyy-MM-dd',
'projection.date_created.interval' = '1',
'projection.date_created.interval.unit' = 'DAYS'
)
この範囲指定で気をつけなければいけないのが、 日付型のパーティションカラムは、クエリ実行時間の協定世界時(UTC)を基準に生成される という点です。こちらは公式ドキュメントに注意書きがありました。
Projected date columns are generated in Coordinated Universal Time (UTC) at query execution time.
Supported Types for Partition Projection - Amazon Athena
要は日本時間で00時00分〜08時59分の間にクエリが実行されると、そのタイミングのNOW
は前日になってしまう、ということです。午前中にバッチジョブを動かすケースをよくあると思うので、Partition Projectionを使用する際は注意が必要ですね。
念のため先ほどのテーブルへINSERTクエリを発行するLambda関数を作成し、EventBridgeで1時間ごとに起動して挙動を確認してみました。AthenaとS3への権限を付与したIAM Roleをアタッチし、タイムアウトを5分に設定したLambdaで、以下のPython関数を実行します。
import boto3
import uuid
import time
from datetime import datetime as dt, timezone as tz, timedelta as td
client = boto3.client('athena')
database = 'cm-haruta'
output='s3://cm-haruta/athena_results'
workgroup = 'primary'
def lambda_handler(event, context):
id = uuid.uuid4()
dt_now = dt.now(tz(td(hours=9)))
today = dt_now.date()
query = f'''
INSERT INTO "cm-haruta"."partition_error"
VALUES ('{id}', '{dt_now}', '{today}')
'''
print("following query excecuted: ")
print(query)
# Execution
exec_id = client.start_query_execution(
QueryString=query,
QueryExecutionContext={
'Database': database
},
ResultConfiguration={
'OutputLocation': output,
},
WorkGroup=workgroup
)["QueryExecutionId"]
status = client.get_query_execution(QueryExecutionId=exec_id)["QueryExecution"]["Status"]
print("Athena Execution ID: {}".format(exec_id))
print("Workgroup: {}".format(workgroup))
while status["State"] not in ["SUCCEEDED", "FAILED", "CANCELLED"]:
print('{}: wait query running...'.format(status["State"]))
time.sleep(5)
status = client.get_query_execution(QueryExecutionId=exec_id)["QueryExecution"]["Status"]
print(status["State"])
if not status["State"] == 'SUCCEEDED':
print('Execution ID: ' + exec_id)
print('Detail: ' + status['StateChangeReason'])
raise Exception('Athena Query Failed')
print(status)
return 'OK'
結果、やはり00時00分〜08時59分間の実行は、全てGENERIC_INTERNAL_ERROR
となっていました。09時52分の実行からパーティションへのインサートに成功しています。
id | time | date_created |
---|---|---|
9f18ccb8-087d-4207-9325-7d1f2e314cb0 | 2021-11-01 17:52:32.098482+09:00 | 2021-11-01 |
feae989b-3fec-47ef-8cab-26a2fa3407b8 | 2021-11-01 18:52:31.927325+09:00 | 2021-11-01 |
9b938cec-c567-4c9e-bf6d-e4d5207970e8 | 2021-11-01 19:52:31.962782+09:00 | 2021-11-01 |
785de808-cf6c-4b82-a99a-077aefb116ec | 2021-11-01 20:52:32.248542+09:00 | 2021-11-01 |
a1c367c2-fd30-4678-a28f-534bf5c6a8f9 | 2021-11-01 21:52:32.271044+09:00 | 2021-11-01 |
49f46a41-8d03-4ce1-a157-e4c6cd62e51d | 2021-11-01 22:52:32.237517+09:00 | 2021-11-01 |
a13758d8-634c-4ab3-a9c1-919ab8ab8609 | 2021-11-01 23:52:32.088840+09:00 | 2021-11-01 |
1c1ac2ef-e43a-4199-8213-d853d6fa980b | 2021-11-02 09:52:32.219154+09:00 | 2021-11-02 |
解決方法
解決方法は至って簡単で、パーティションの範囲を1日伸ばしておけばOKです。具体的には、'projection.date_created.range' = '2018-03-01,NOW+1DAY'
とするだけ。この辺り、Partition Projectionはかなり柔軟に設定が可能です。
TBLPROPERTIES (
'has_encrypted_data' = 'false',
'projection.enabled' = 'true',
'projection.date_created.type' = 'date',
'projection.date_created.range' = '2018-03-01,NOW+1DAY',
'projection.date_created.format' = 'yyyy-MM-dd',
'projection.date_created.interval' = '1',
'projection.date_created.interval.unit' = 'DAYS'
)
設定項目の細かい詳細については、公式ドキュメントをご覧ください。
Supported Types for Partition Projection - Amazon Athena
気になった点
そもそもPartition ProjectionはMSCK REPAIR
などで更新する実体のパーティション情報とは別の存在だと思っていたので、Partition Projectionの設定がINSERT時のパーティションに影響を及ぼしている点がちょっと不可解です。このケースにおいてエラーを出すかどうかは、Athenaの開発チームの匙加減で決められたんですかねー。