見出し画像

Athenaの自動パーティショニングをPartition Projectionで実現する

先日「AthenaとRedashで遅いAPIのレスポンスタイムを可視化する」という記事を書きました。

記事中では、

パーティショニングをするには、
・ALTER TABLE ADD PARTITION, MSCK REPAIR TABLEコマンドを打つ
・Glueのクローラーを利用する
の2つの方法があって、ノーコードで自動で行うにはGlueクローラーを利用する必要がある。
ただし、Glueクローラーを利用するにはディレクトリ構成がHive形式になっていることが前提となっていて、ALBのログ出力はHive形式となっていないためマニュアルで対応する必要がある。

と記載しましたが、この記事を読んでくれた元同僚から

Partition Projectionを利用すれば自動パーティショニングできそうです」

というアドバイスを頂きました。

(2020/06にリリースされたばかりの新しい機能だったので当時調査したときにはなかった)

試してみたところ自動でパーティショニングが実現できたので以降でALBのログを例にとって紹介したいと思います。

どうやるの??

DDLだけで完結します!
具体的には、DDLで TBLPROPERTIESを指定し、projection.xxx という属性を設定するだけです。
Glueなど他サービスを使う必要もHive形式のディレクトリ構成にする必要もありません。

ALBのログのディレクトリ構成は、

s3://<bucket_name>/AWSLogs/<account_id>/elasticloadbalancing/<region>/YYYY/MM/DD

という形式になるので、これを日次でパーティショニングする例は以下のとおりです。

PARTITIONED BY ( 
 date_day STRING
)
.
.
.
TBLPROPERTIES (
 "projection.enabled" = "true",
 "projection.date_day.type" = "date",
 "projection.date_day.range" = "2020/08/01,NOW",
 "projection.date_day.format" = "yyyy/MM/dd",
 "projection.date_day.interval" = "1",
 "projection.date_day.interval.unit" = "DAYS",
 "storage.location.template" = "s3://<bucket_name>/AWSLogs/<account_id>/elasticloadbalancing/<region>/${date_day}"
)

これで date_day がパーティションとして利用できるようになったので以下のようなDMLでパーティションを利用した結果の取得が可能になります。

SELECT *
FROM "alb_logs"
WHERE date_day = '2020/08/05' limit 10;

最終的なDDLは以下になりました。

CREATE EXTERNAL TABLE `alb_logs`(
 `type` string COMMENT '', 
 `request_timestamp` string COMMENT '', 
 `elb_name` string COMMENT '', 
 `client_addrport` string COMMENT '', 
 `client_ip` string COMMENT '', 
 `client_port` int COMMENT '', 
 `target_addrport` string COMMENT '', 
 `target_ip` string COMMENT '', 
 `target_port` int COMMENT '', 
 `request_processing_time` string COMMENT '', 
 `target_processing_time` string COMMENT '', 
 `response_processing_time` string COMMENT '', 
 `elb_status_code` string COMMENT '', 
 `target_status_code` string COMMENT '', 
 `received_bytes` int COMMENT '', 
 `sent_bytes` int COMMENT '', 
 `request` string COMMENT '', 
 `user_agent` string COMMENT '', 
 `ssl_cipher` string COMMENT '', 
 `ssl_protocol` string COMMENT '', 
 `target_group_arn` string COMMENT '', 
 `trace_id` string COMMENT '', 
 `domain_name` string COMMENT '', 
 `chosen_cert_arn` string COMMENT '', 
 `matched_rule_priority` string COMMENT '', 
 `request_creation_time` string COMMENT '', 
 `actions_executed` string COMMENT '', 
 `redirect_url` string COMMENT '')
PARTITIONED BY ( 
 `date_day` string)
ROW FORMAT SERDE 
 'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ( 
 'input.regex'='([^ ]*) ([^ ]*) ([^ ]*) (([^ ]*):([^ ]*)|-) (([^ ]*):([^ ]*)|-) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) \"([^\\\"]*)\" \"([^\\\"]*)\" ([^ ]*) ([^ ]*) ([^ ]*) \"([^\\\"]*)[ ]*\" \"([^ ]*)\" \"([^ ]*)\" ([^ ]*) ([^ ]*) \"([^ ]*)\" \"([^\\\"]*)\".*$') 
STORED AS INPUTFORMAT 
 'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
 's3://<s3_bucket>/AWSLogs/<account_id>/elasticloadbalancing/<region>'
TBLPROPERTIES (
 'has_encrypted_data'='false', 
 'projection.date_day.format'='yyyy/MM/dd', 
 'projection.date_day.interval'='1', 
 'projection.date_day.interval.unit'='DAYS', 
 'projection.date_day.range'='2020/01/01,NOW', 
 'projection.date_day.type'='date', 
 'projection.enabled'='true', 
 'storage.location.template'='s3://<s3_bucket>/AWSLogs/<account_id>/elasticloadbalancing/<region>/${date_day}', 
)

また、今回は日付型(date)を利用していますが、他に 列挙型, 整数型, 挿入型が利用できるようです。

Glueクローラーとの使い分け

クラスメソッドさんの記事にわかりやすく解説されていますが、Athenaを介してのみテーブルを参照するのであればほとんどのシーンで Partition Projectionを選んでおけば良さそうです。(Glueクローラー動かすと課金もされますし...)

おわりに

Partition Projection、あまり話題になってないように見えますが積極的に使っていくのが吉だと思います!
弊noteで利用しているAthenaのテーブルも順次Partition Projection方式に切り替えていく予定です。

弊noteをよりよいサービスにするために、技術書購入や勉強会・セミナー参加の費用にあてたいと思います🙏