Partition Projection を使って AWS WAF のログを分析してみた

Partition Projection で Athena のコストと手間を最適化します!
2020.09.14

Amazon Athena (以降、Athena) の利用料金とパフォーマンスは、スキャン対象のデータ量に比例します。 Athena では、パーティションを追加することによって、スキャン対象のデータ量を絞り、コストを減らしスキャン速度を向上できます。
パーティションを追加するには、

  • ALTER TABLE ADD PARTITION を実行
  • Glueのクローラで Glue Data Catalog にパーティションを登録

といった方法がございますが、これらはクエリを実行する度に実行しなくてはなりません。
また、多くのパーティションが存在するケースでは Glue Data Catalog からパーティションを取得する API の呼び出しがクエリパフォーマンスのボトルネックとなる可能性がございました。

これらの課題を解決するために Partition Projection を使うことで、パーティション化されたテーブルのクエリ処理を高速化し、パーティション管理を自動化することができます。詳細は以下のブログを参照ください。

本記事では、AWS WAF のログを Athena で分析するのに、Partition Projection を使ってコストと手間を効率化する方法を紹介します。

やってみた

まず Athena でテーブルを作成します。テーブル定義は以下のブログをベースにしております。

39行目から46行目で、Partition Projection の設定をしています。

CREATE EXTERNAL TABLE IF NOT EXISTS waflogs_all_partitioned
(
`timestamp` bigint,
formatVersion int,
webaclId string,
terminatingRuleId string,
terminatingRuleType string,
action string,
terminatingRuleMatchDetails array < struct <
    conditionType: string,
    location: string,
    matchedData: array < string >
> >,
httpSourceName string,
httpSourceId string,
ruleGroupList array < struct <
    ruleGroupId: string,
    terminatingRule: struct < ruleId: string, action: string >,
    nonTerminatingMatchingRules: array < struct < action: string, ruleId: string > >,
    excludedRules: array < struct < exclusionType: string, ruleId: string > >
> >,
rateBasedRuleList array < struct < rateBasedRuleId: string, limitKey: string, maxRateAllowed: int > >,
nonTerminatingMatchingRules array < struct < action: string, ruleId: string > >,
httpRequest struct <
    clientIp: string,
    country: string,
    headers: array < struct < name: string, value: string > >,
    uri: string,
    args: string,
    httpVersion: string,
    httpMethod: string,
    requestId: string
>
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://aws-waf-logs-123456789012/${date}'
PARTITIONED BY ( 
  `date` string)
TBLPROPERTIES (
  'projection.enabled' = 'true',
  'projection.date.type' = 'date',
  'projection.date.range' = 'NOW-1YEARS,NOW',
  'projection.date.format' = 'yyyy/MM/dd',
  'projection.date.interval' = '1',
  'projection.date.interval.unit' = 'DAYS',
  'storage.location.template' = 's3://aws-waf-logs-123456789012/${date},
  'classification'='csv', 
  'compressionType'='gzip', 
  'delimiter'='|', 
  'typeOfData'='file');

Partitioned されたテーブルが作成されました。

では、クエリを投げてみます。特定の日付けのカウントログを出力します。

SELECT from_unixtime(timestamp/1000, 'Asia/Tokyo') AS JST, * 
FROM waflogs, UNNEST(nonTerminatingMatchingRules) t(nonTermRule) 
WHERE nonTermRule.action = 'COUNT' AND date = '2020/09/07';

出力できていることを確認できました。

さいごに

Partition Projection を使った、WAF ログの分析をやってみました。
パーティションを使うことで Athena のコストを最適化できますが、Partition Projection を使うことでパーティション追加手順も不要にできました。 特定の日や時間に絞って都度テーブルすることもできますが、複数の日や時間にまたがって分析するにはパーティションを作ることが有効ですので、ぜひ活用ください!

参考