こんにちは、masm11 です。 今回は AWS Athena のパーティションの設定方法について説明したいと思います。
まず Athena とは
Cloudwatch Logs やその他の場所でログが発生すると、 手軽に検索したくなりますよね。
そういう場合、S3 に置いておくと Athena で SQL を使って検索できます。
発生したログはただのテキストだと思いますので、なんとかして以下のように JSON にしておきます。Cloudwatch Logs に溜まっているなら、Firehose から Lambda を使うのが良いでしょう。
{"timestamp":"2021-04-24T22:50:45","message":"test log 1"} {"timestamp":"2021-04-24T22:51:00","message":"test log 2"}
こういうファイルをたくさん S3 に溜めておきます。
Athena では以下のように設定します。
CREATE EXTERNAL TABLE logs ( timestamp string, message string ) ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' LOCATION 's3://bucket/logs';
こうすると、SQL を使って検索できます。
SELECT * FROM logs WHERE message LIKE 'test log%';
ただし、ここで重大な問題があります。この SQL でスキャンしたデータ量で 料金が発生するのです。なんとかしてスキャンする量を絞る必要があります。
そこでパーティションの出番です。
設定方法その1
S3 バケットの中を以下のように構造化しておきます。 Hive 形式と呼ばれるものです。
s3://bucket/logs/year=YYYY/month=MM/day=DD/file.ext
year=
等はそのままプレフィックスに含めます。YYYY
等は
数字に置き換えます。つまり、プレフィックスには year=2021
等という
文字列が含まれるわけですね。
そして、CREATE EXTERNAL TABLE
は以下のように実行します。
CREATE EXTERNAL TABLE logs ( timestamp string, message string ) PARTITIONED BY (year STRING, month STRING, day STRING) ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' LOCATION 's3://bucket/logs';
その後、
MSCK REPAIR TABLE logs;
を実行します。これで S3 のファイル名がスキャンされて、パーティションの 一覧が作成されます。この時には料金はかかりません。
これで準備ができました。あとは SELECT するだけです。
SELECT * FROM logs WHERE year = '2021' AND month = '04' AND day = '24' AND message LIKE 'test log%';
こうすると、2021-04-24 のログだけがスキャンされます。
ただし、プレフィックスが増えた時には MSCK REPAIR TABLE
をしてやる
必要があります。
MSCK REPAIR TABLE
だと、ファイル数が増えてくると時間がかかりますので、
代わりに ALTER TABLE ADD PARTITION
を使っても良いでしょう。
その場合は、プレフィックスが不要になった場合は ALTER TABLE DROP PARTITION
をする必要があります。しなくてもエラーは発生しませんが、
パーティションが増えると検索が遅くなります。
設定方法その2
設定方法その1は、パーティションのメンテが手間なんですよね。 そこで2つめの方法です。
s3://bucket/logs/YYYY/MM/DD/file.ext
year=
等がなくなり、シンプルになりましたね。
CREATE EXTERNAL TABLE
は以下のようになります。
CREATE EXTERNAL TABLE logs ( timestamp string, message string ) PARTITIONED BY ( year INT, month INT, day INT ) ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' LOCATION 's3://bucket/logs' TBLPROPERTIES ( 'projection.enabled' = 'true', 'projection.year.type' = 'integer', 'projection.year.range' = '2021,2100', 'projection.year.digits' = '4', 'projection.month.type' = 'integer', 'projection.month.range' = '1,12', 'projection.month.digits' = '2', 'projection.day.type' = 'integer', 'projection.day.range' = '1,31' 'projection.day.digits' = '2', 'storage.location.template' = 's3://bucket/logs/${year}/${month}/${day}' );
随分長くなりました。
'projection.day.type' = 'integer', 'projection.day.range' = '1,31' 'projection.day.digits' = '2',
day
は整数で、1〜31 で、2桁であることを宣言しています。桁数が足りなければ 0 でパディングされます。
準備はこれで終わりです。検索はその1とだいたい同じですが、年月日は整数になります。
SELECT * FROM logs WHERE year = 2021 AND month = 4 AND day = 24 AND message LIKE 'test log%';
そしてこちらの方法はパーティションのメンテは不要です。
ただし、パーティションのキーはあらかじめ範囲を決めておく必要があります。つまり、
'projection.year.range' = '2021,∞',
なんて指定はできません。
まとめ
Athena のパーティションの設定方法を2つ紹介しました。 特に理由がなければ後者で良いと思います。
インゲージではエンジニアを募集しています。詳細は以下のページへ!