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

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

Clock Icon2022.07.05 14:55

この記事は公開されてから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による範囲計算)で実装してみます。

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します。

    (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で日付パーティション範囲のタイムゾーン対応をしてみました。

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

参考

以上

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.