Amazon AthenaのPartition Projectionで日付パーティション範囲のタイムゾーン対応をする

2022.07.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、Amazon AthenaのPartition Projectionで日付パーティション範囲のタイムゾーン対応をしてみました。

Partition Projectionの日付計算はUTCで行われる

Amazon AthenaのPartition ProjectionではDate typeに対応していますが、タイムゾーンの指定はUTC時間のみとなります。

Projected date columns are generated in Coordinated Universal Time (UTC) at query execution time.

よって例えばデータの日付パーティションを日本時間で作成していても、パーティションの射影範囲の指定でNOWを使用すると計算に用いられるタイムゾーンは必ずUTC時間となり、想定した範囲でパーティショニングがされなくなってしまいます。

そこで、日付パーティション範囲に対して相対日付文字列(relative date strings)を指定することにより、日本時間に対応できるようにしてみます。

やってみた

環境準備

AWS CDK v2(TypeScript)で次のCDKスタックを作成します。まずはタイムゾーン未対応(UTCによる範囲計算)で実装してみます。

lib/process-stack.ts

import { Construct } from 'constructs';
import {
  aws_s3,
  aws_athena,
  RemovalPolicy,
  Stack,
  StackProps,
} from 'aws-cdk-lib';
import * as glue from '@aws-cdk/aws-glue-alpha';

export class ProcessStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // ソースデータ格納バケット
    const sourceDataBucket = new aws_s3.Bucket(this, 'sourceDataBucket', {
      bucketName: `data-${this.account}`,
      removalPolicy: RemovalPolicy.DESTROY,
    });

    // Athenaクエリ結果格納バケット
    const athenaQueryResultBucket = new aws_s3.Bucket(
      this,
      'athenaQueryResultBucket',
      {
        bucketName: `athena-query-result-${this.account}`,
        removalPolicy: RemovalPolicy.DESTROY,
      },
    );

    // データカタログ
    const dataCatalog = new glue.Database(this, 'dataCatalog', {
      databaseName: 'data_catalog',
    });

    // データカタログテーブル
    const sourceDataGlueTable = new glue.Table(this, 'sourceDataGlueTable', {
      tableName: 'source_data_glue_table',
      database: dataCatalog,
      bucket: sourceDataBucket,
      s3Prefix: 'data/',
      partitionKeys: [
        {
          name: 'dt',
          type: glue.Schema.STRING,
        },
      ],
      dataFormat: glue.DataFormat.JSON,
      columns: [
        {
          name: 'userId',
          type: glue.Schema.STRING,
        },
        {
          name: 'count',
          type: glue.Schema.FLOAT,
        },
      ],
    });

    // データカタログテーブルへのPartition Projectionの設定
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (sourceDataGlueTable.node.defaultChild as any).tableInput.parameters = {
      'projection.enabled': true,
      'projection.dt.type': 'date',
      'projection.dt.range': '2022/07/05/00,NOW', //タイムゾーン未対応
      'projection.dt.format': 'yyyy/MM/dd/HH',
      'projection.dt.interval': 1,
      'projection.dt.interval.unit': 'HOURS',
      'storage.location.template':
        `s3://${sourceDataBucket.bucketName}/data/` + '${dt}',
    };

    // Athenaワークグループ
    new aws_athena.CfnWorkGroup(this, 'athenaWorkGroup', {
      name: 'athenaWorkGroup',
      workGroupConfiguration: {
        resultConfiguration: {
          outputLocation: `s3://${athenaQueryResultBucket.bucketName}/result-data`,
        },
      },
    });
  }
}
  • パーティション範囲は2022/07/05/00からNOWを指定しています。

上記をCDK Deployしてスタックをデプロイします。

データソースとなるバケットのdata/2022/07/05/パス配下で、次のHHに対応したフォルダにそれぞれデータを格納します。

  • 12
  • 15
  • 18
  • 21

タイムゾーン未対応の場合

Athenaのコンソールで以下のクエリを実行し、パーティション射影が行われている全てのデータを取得してみます。

SELECT *
FROM data_catalog.source_data_glue_table

するとパーティションが2022/07/05/12のデータのみ取得されました。

クエリ実行時点の時間はJST23時です。よってNOWはUTC14時となり、日付パーティションのHHの範囲が00から14の間の12のデータのみが取得される動作となりました。

タイムゾーン(JST)対応した場合

それではタイムゾーン対応をしてみます。CDKのPartition Projectionの構成を次のように変更し、Deployします。

lib/process-stack.ts

    (sourceDataGlueTable.node.defaultChild as any).tableInput.parameters = {
      'projection.enabled': true,
      'projection.dt.type': 'date',
      'projection.dt.range': '2022/07/05/00,NOW+9HOURS', //タイムゾーン対応(日本時間)
      'projection.dt.format': 'yyyy/MM/dd/HH',
      'projection.dt.interval': 1,
      'projection.dt.interval.unit': 'HOURS',
      'storage.location.template':
        `s3://${sourceDataBucket.bucketName}/data/` + '${dt}',
    };
  • パーティション範囲の終了をNOW+9HOURSとすることにより、JST(UTC+0900)の時間を自動計算するようにしています。

先ほどと同じクエリを実行します。

SELECT *
FROM data_catalog.source_data_glue_table

すると今度は2022/07/05/122022/07/05/152022/07/05/182022/07/05/21のデータが取得できました!

NOW23として計算され、12から21までの日付パーティションが射影範囲となりました。

おわりに

Amazon AthenaのPartition Projectionで日付パーティション範囲のタイムゾーン対応をしてみました。

ドキュメントを見るとパーティション範囲の指定はある程度柔軟に記述できるようです。気になる方は読み込んでみてください。

参考

以上