こんにちは、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/12
、2022/07/05/15
、2022/07/05/18
、2022/07/05/21
のデータが取得できました!
NOW
が23
として計算され、12
から21
までの日付パーティションが射影範囲となりました。
おわりに
Amazon AthenaのPartition Projectionで日付パーティション範囲のタイムゾーン対応をしてみました。
ドキュメントを見るとパーティション範囲の指定はある程度柔軟に記述できるようです。気になる方は読み込んでみてください。
参考
以上