なになれ

IT系のことを記録していきます

Athenaでパーティションを楽に作成する方法

以前にAthenaの記事を投稿した時にパーティションの作り方として、Lambda関数からAthenaのクエリを実行する方法を紹介しました。
hi1280.hatenablog.com このやり方よりも簡単にパーティションを作成する方法を今回は紹介します。
内容としては、パーティション射影という機能を使います。

docs.aws.amazon.com

こちらを使うと毎回パーティションを作る処理を実行することなく、自動的にパーティションを作ることが可能になります。

セットアップ

パーティション射影の機能を使うには、テーブルを作成するときに特別な設定を行う必要があります。
今回はALBのアクセスログに合わせたテーブルを作成することを題材にします。

テーブルを作成するクエリは以下のとおりです。

CREATE EXTERNAL TABLE `alb_logs_partition_projection`(
  `type` string, 
  `time` string, 
  `elb` string, 
  `client_ip` string, 
  `client_port` int, 
  `target_ip` string, 
  `target_port` int, 
  `request_processing_time` double, 
  `target_processing_time` double, 
  `response_processing_time` double, 
  `elb_status_code` string, 
  `target_status_code` string, 
  `received_bytes` bigint, 
  `sent_bytes` bigint, 
  `request_verb` string, 
  `request_url` string, 
  `request_proto` string, 
  `user_agent` string, 
  `ssl_cipher` string, 
  `ssl_protocol` string, 
  `target_group_arn` string, 
  `trace_id` string, 
  `domain_name` string, 
  `chosen_cert_arn` string, 
  `matched_rule_priority` string, 
  `request_creation_time` string, 
  `actions_executed` string, 
  `redirect_url` string, 
  `lambda_error_reason` string, 
  `target_port_list` string, 
  `target_status_code_list` string, 
  `new_field` string)
PARTITIONED BY ( 
  `year` int, 
  `month` int, 
  `day` int)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ( 
  'input.regex'='([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" \"([^\"]*)\" ([A-Z0-9-]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^ ]*)\" \"([^s]+)\" \"([^s]+)\"(.*)') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://your-alb-logs-directory/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/ap-northeast-1'
TBLPROPERTIES (
  'has_encrypted_data'='false', 
  'projection.enabled'='true', 
  'projection.day.digits'='2', 
  'projection.day.interval'='1', 
  'projection.day.range'='1,31', 
  'projection.day.type'='integer', 
  'projection.month.digits'='2', 
  'projection.month.interval'='1', 
  'projection.month.range'='1,12', 
  'projection.month.type'='integer', 
  'projection.year.digits'='4', 
  'projection.year.interval'='1', 
  'projection.year.range'='2020,2025', 
  'projection.year.type'='integer', 
  'storage.location.template'='s3://your-alb-logs-directory/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/ap-northeast-1/${year}/${month}/${day}'
)

パーティション射影を設定するには、TBLPROPERTIESに設定していきます。
projection.enabledがtrueでパーティション射影を行うことを指定します。
今回のパーティションはyear、month、dayになります。それぞれにどのようにパーティションを作成するかを設定します。

たとえば、dayの場合について説明します。
projection.day.digitsで値が2桁であることを指定します。
projection.day.intervalでパーティション値の間隔を指定します。dayは1ずつ変化するため、1を指定します。
projection.day.rangeは値の最小値から最大値の範囲を指定します。dayの場合は、1から31になります。
projection.day.typeは値の型を指定します。ここでは、integerを指定して、値として整数値を期待します。

データがあるS3のロケーションとパーティションの値を関連づけるために、storage.location.templateを指定します。
${}の指定をすることで、パーティション値とS3のロケーションを関連づけることができます。

ここまでの内容で、year、month、dayのパーティション射影を設定すると、パーティションを自動で作成することができます。

動作確認

以下のようにパーティションを条件に加えて検索することで、パーティションが機能した状態でクエリが実行されます。

SELECT * FROM "default"."alb_logs_partition_projection" where year = 2021 and month = 2 and day = 27;

まとめ

今までAthenaでパーティションを作るのが面倒だと思っていましたが、パーティション射影を使うことでかなり楽ができそうです。