LambdaからAthenaのパーティション読み込みを行う際に躓いたこと

はじめに

Athenaで作成済みのテーブル(パーティション化)について、Lmabdaからパーティション読み込みを行うクエリの実装中に躓いたことをまとめます。

Lambdaのランタイムはpythonになります。

起きたこと

下記コードのとおりパーティション読み込みクエリを実行するコードを実装して、Lambdaで実行したところエラー(例外)が発生しました。

同じクエリをAWSコンソールのAthenaから実行した場合、エラーにはなりませんでした。

# コード
table_name = 'table_a'
query = f'MSCK REPAIR TABLE {table_name};'
start_query_execution_response = athena.start_query_execution(
  QueryString=query,
  QueryExecutionContext={
    'Database': os.getenv('ATHENA_DATABASE'),
  },
  ResultConfiguration={
    'OutputLocation': os.getenv('ATHENA_OUTPUT')},
  WorkGroup=os.getenv('ATHENA_WORKGROUP')]
)
execution_id = start_query_execution_response['QueryExecutionId']

# 実行完了までポーリングする必要があります
get_query_execution_response = athena.get_query_execution(
          QueryExecutionId=execution_id)
# エラー内容
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask

エラー原因

Lambdaの実行ロールの権限不足が上記エラーの原因でした。

今回のエラーが発生するまでは、権限不足の状態でLambdaを実行すると権限不足に関するエラーメッセージが出力されていたので、ポリシー設定は都度ググりながら対応していました。

不足していた権限

  1. default データベースに対する権限の付与
  2. Glue のデータベースおよびテーブルに対する権限不足
  3. ソースの S3 に対するの権限不足

default データベースに対する権限の付与

下記ステートメントが不足していました。

  {
        "Effect": "Allow",
        "Action": [
            "glue:GetDatabase",
            "glue:CreateDatabase"
        ],
        "Resource": [
            "arn:aws:glue:ap-northeast-1:123456789012:catalog",
            "arn:aws:glue:ap-northeast-1:123456789012:database/default"
        ]
    }

Glue のデータベースおよびテーブルに対する権限不足

glue:GetDatabase および glue:BatchCreatePartition のみ定義しており、全てを網羅できていませんでした。

 {
      "Action": [
        "glue:GetDatabase",
        "glue:GetTable",
        "glue:GetPartitions",
        "glue:GetPartition",
        "glue:BatchCreatePartition"
      ],
      "Resource": [
        "arn:aws:glue:ap-northeast-1:123456789012:catalog",
        "arn:aws:glue:ap-northeast-1:123456789012:database/database_name",
        "arn:aws:glue:ap-northeast-1:123456789012:table/database_name/table_name"
      ],
      "Effect": "Allow"
    }

ソースの S3 に対するの権限不足

s3:ListBucket 権限が不足していました。

{
      "Action": [
        "s3:DeleteObject*",
        "s3:PutObject",
        "s3:PutObjectLegalHold",
        "s3:PutObjectRetention",
        "s3:PutObjectTagging",
        "s3:PutObjectVersionTagging",
        "s3:Abort*",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::bucket_name",
        "arn:aws:s3:::bucket_name/*"
      ],
      "Effect": "Allow"
    },

他のパーティション読み込み方法で対応

上記の例では、 MSCK REPAIR TABLE によるパーティション読み込みを検討していましたが

ALTER TABLE ADD PARTITION を利用することで上記エラーが発生せずに実装することができました。

パーティション読み込みを行う4つの方法

  1. MSCK REPAIR TABLE クエリ
  2. ALTER TABLE ADD PARTITIONクエリ
  3. AWS Glue crawler
  4. パーティション射影(partition projection)

詳細は、Athena でのデータのパーティション化ユースケースに適したアプローチで、データカタログにパーティションをロードするを確認すると良いかと思います。

ALTER TABLE ADD PARTITIONクエリ

今回、Hiveスタイル形式のS3ソースを対象としていたので、

MSCK REPAIR TABLE クエリを使用することを検討していました。

しかし、冒頭のエラーが発生し改めてパーティション読み込みについて調査したところ、 ALTER TABLE を使用する方が良さそうだと今回は判断しました。

判断した理由

  • ALTER TABLE ADD PARTITIONクエリは、Hiveや非Hiveのどちらでも使用可能。
  • MSCK REPAIR TABLE クエリはパーティションの数が多くなる場合、クエリがタイムアウトする可能性があるため避けたい。実行毎に全てのパーティションが比較の対象となるため。
  • パーティション射影の場合、空のパーティションが多くなる可能性があるため避けたい。

下記はALTER TABLE ADD PARTITIONクエリのコードの一部です。

クエリの実行と結果取得は上記コードと同じロジックになります。

date をパーティションの文字列とする場合は、おそらくエスケープする必要があります。

予約ワードを含むクエリの例

query = f"ALTER TABLE {table_name} ADD IF NOT EXISTS PARTITION (hogedate= '{hogedate}') LOCATION '{partition_path}';"

まとめ

エラーの原因が権限不足だったので、改めてしっかりとドキュメントを読み込み必要性があると感じました。一応、権限に関する公式ドキュメントを確認しながら実装していたのですが、所々足りませんでした。

パーティション読み込みにも複数アプローチがあるので、適宜使い分けられるようにしたいと思います。

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!