【AWS】用語を整理しながら学ぶAWS Amazon Athena

## はじめに

この記事では AWSが提供するAmazon Athena(以下、Athena)を学習していく記事です。主な内容としては実践したときのメモを中心に書きます。（忘れやすいことなど）
誤りなどがあれば書き直していく予定です。

## Athenaとは何なのか

簡単に1行で表現すると
`AthenaはSQL を使用した S3 でのデータクエリ`と表現されています。

公式では以下のように説明されています。

> Amazon Athena は、オープンソースフレームワーク上に構築されたサーバーレスのインタラクティブな分析サービスで、オープンテーブルとファイル形式をサポートしています。Athena は、ペタバイト規模のデータが存在する場所で分析するための簡素化された柔軟な方法を提供します。Amazon Simple Storage Service (S3) データレイクと 25 以上のデータソース (オンプレミスデータソースや SQL または Python を使用した他のクラウドシステムを含む) からデータを分析したり、アプリケーションを構築したりできます。Athena は、オープンソースの Trino および Presto エンジンと Apache Spark フレームワーク上に構築されており、プロビジョニングや設定は不要です。

要するにストレージサービスやデータベースと連携してサーバレスに分析をSQLで実行できるサービスです。内部ではAthenaエンジンが動作していますが、実態はオープンソースの Trino および Presto エンジンと Apache Spark フレームワークです。
なお、計算用のインスタンスをプロビジョニングする必要はありません。

サーバーレスのインタラクティブな分析サービス？SQL?Athenaエンジン？Trino？Prestoエンジン？Apache Spark フレームワーク？

何もわからないですね。では一つ一つ見ていきましょう。

## [前提知識] SQLについておさらい

Athenaを語る上で、はずせない基礎的な技術としてはSQLがあります。
SQLというと何を思い浮かべるでしょうか。たぶん、多くの人がリレーショナルデータベースを思い浮かべると思います。どんなものだったかここでおさらいしておきましょう。

### SQLは3種類に区別できる

SQLにはさまざまな文法がありますが、3種類に分類できます。

- DDL(Data Definition Language)
    - データの定義、データベースオブジェクトの生成（CREATE/DROP/ALTER）
- DML(Data Manipulation Language)
    - データの取得・更新・削除（SELECT/INSERT/UPDATE/DELETE）
- DCL(Data Control Language)
    - トランザクション（Begin/Commit/ROLLBACK）

### 集計ができる

`GROUP BY`によるデータのグループ化が可能なため、特定の属性でデータを集計できます。
なお、集計には集計関数がよく用いられます。

- COUNT
    - 数を数える
- SUM
    - 数値を合計する
- MAX
    - 最大値を算出する
- MIN
    - 最小値を算出する
- AVG
    - 平均値を算出する

また、後ほど説明する`Where`や`Having`を利用しない条件付きの集計も可能です。
具体的には下記の通りです。

```SQL
-- CASE WHEN を使う
CASE name
    WHEN 'Yamada' THEN 65536
    WHEN 'Tanaka' THEN 123
    ELSE 99
END

-- こんな方法もある
CASE
    WHEN name = 'Yamada' THEN 65536
    WHEN name = 'Tanaka' THEN 123
    ELSE 99
END

```

`GROUP BY`によるデータのグループ化を利用すると条件付きもしくは条件なしの集計カラムを作成できます。

### 検索条件の設定

`WHERE`や`Having`を使った検索条件の設定が可能です。
`HAVING`は`GROUP BY`を使った際に利用するものであり、グループ化された結果に対して条件を設定します。

グループ化される前は`WHERE`、グループ化された後は`HAVING`を使うと覚えておくと良いでしょう。

### その他文法

他にも`CREATE`や`INSERT INTO`、`UPDATE`や`DELETE`などさまざまですが、データを取り出すだけであれば、`SELECT`だけでの知識で問題ありません。

## Athenaの特徴

### ワークグループとは

基本をおさらいしたところで、Athenaを利用する上で重要なワークグループについて見ていきましょう。ワークグループとはAthenaのクエリを束ねるグループのことであり、実行履歴の管理やクエリを修正・管理します。

実行したクエリをデバッグするために必要な項目になるので覚えておきましょう。

### AthenaのSQLについて

Athenaで使うSQLとリレーショナルデータベースで使うSQLは同じものでしょうか。
これは半分Yes半分Noです。ほとんどの場合において他のデータベースサービスで利用したSQLがAthenaのSQLで使えます。

半分Noである理由としては似たようなデータベースサービス同士でも文法やデータ型の扱いが異なったりなど細かい違いがあります。

### Athenaエンジンとは何なのか

この細かい違いを認識するためにはまず、`Athenaエンジンとは何なのか`について知る必要があります。

公式サイトに書いてあるとおり、`Athena は、オープンソースの Trino および Presto エンジンと Apache Spark フレームワーク上に構築`されているので`Athenaエンジン＝Trino および Presto エンジン`といえます。なお、現時点でAthenaエンジンのバージョンはV2とV3に分かれます。

ここでようやく`Trino`とそして、`Presto`という2つのワードが登場！
次に、Athenaエンジンを理解する上で重要な２つのワードについて説明します。

### Trinoとは

とても可愛いうさぎのマスコットが飾られているサイトですが、公式サイトです。

https://trino.io/

Trinoは`異なるデータソースに対しても高速でインタラクティブに分析ができる高性能分散SQLエンジン`とよく言われています。

ビッグデータの分析基盤を支えている重要なOSSであり、`Trino Software Foundation`を中心にさまざまな企業に支えられています。

Trinoを使うことで`SQL-on-Anything`、つまりはSQLを書けばどんなデータソースでも取り出せるという性質を持っています。

[Presto_SQL_on_Everything.pdf - 参考](https://trino.io/Presto_SQL_on_Everything.pdf)

### Prestoとは

`Trino`という名前に変わる前の名前です。旧名称というところです。

`Trino=Presto`ということになるのでAthenaではPresto（Trino）の関数が利用できます。

元々はFacebook内で開発されたものであり、その後OSSで提供されたという歴史的な背景があります。つまりは`Presto`ときたら現代においては`Trino`ということになります。

### Apache Sparkフレームワーク（Apache Spark）とは

TrinoやPrestoなどを説明してきましたが、Apache Sparkとどうつながるのでしょうか。

そもそもApache Sparkフレームワークとは分散処理フレームワークのことであり、要するに大量のコンピューティングで処理を実行するフレームワークのことです。

この分散処理フレームワーク上でTrino および Prestoが動作すると考えると良いでしょう。
ちなみにHadoopとの違いについてはAWSに記載があります。

[Hadoop と Spark の違いは?](https://aws.amazon.com/jp/compare/the-difference-between-hadoop-vs-spark/)

## 料金体系

公式の`料金体系の仕組み`では以下のように語られています。[参考](https://aws.amazon.com/jp/athena/pricing/)

> クエリ単位の課金では、すぐに開始でき、実行したクエリでスキャンされたデータに対してのみ支払うことができます。

SQLでクエリを実行する人はクエリの料金だけ理解しておけば、問題ありません。
簡単にいえば、`実行したクエリでスキャンされたデータに対してのみ支払う`という料金体系です。

オンデマンドとプロビジョンという2つの提供形態があることには注意が必要ですが
まずは使ってみたいという場合においてはオンデマンド、つまりはプロビジョンは不要です。

なお、プロビジョンおよびApache Sparkの実行にはDPUという単位で料金が発生します。
DPUという料金体系はAWS Glueにもよく登場しますので覚えておきましょう。

## 使い方に関する注意事項

ここまででちょっと使ってみたいな！と思ったと思います。
ですが、Athenaを使う場合はデータカタログを作成する必要があります。

### データカタログとは

メタデータストアなどと言われていますが、簡単に述べるとデータベースです。
AthenaではAWS Glueで作成されたAWS Glue DataCatalogをベースにクエリを実行します。

[AWS Glue](https://qiita.com/ymd65536/items/ce4ea95c96dbf7d29431)については以前に解説しています。

### データカタログの作り方

簡単に説明すると下記の3Stepでカタログを作成および登録できます。

1. S3にCSVを格納
2. AWS Glueでデータを構造化
3. データカタログとして登録

すでにデータカタログが存在する場合はAthena上でDDLのSQLを実行することで既存のデータカタログから新たにデータカタログを作成できます。（これをAthena DDLと呼ぶ）

### Athena DDLとは

新規ではなく既存のデータカタログを作成する場合においてはDDLをAthenaで実行する方が手軽です。

Athena DDLはHiveQL形式で記述する必要があります。下記の例は`action_log`というテーブルを作成してPARQUET形式でS3に保存する例です。

```SQL
CREATE EXTERNAL TABLE IF NOT EXISTS action_log (
    user_id string,
    action_category string,
    action_detail string
)
PARTITIONED BY (year int, month int)
STORED AS PARQUET
LOCATION 's3://athena-examples/action-log/'
TBLPROPERTIES ('PARQUET.COMPRESS'='SNAPPY');
```

[[AWS Black Belt Online Seminar] Amazon Athena - Awsstatic - 参考](https://d1.awsstatic.com/webinars/jp/pdf/services/20200617_BlackBelt_Amazon_Athena.pdf)

なお、HiveQL DDLと似ていますが、厳密には異なります。

[参考：ddl-reference - Amazon Athena](https://docs.aws.amazon.com/ja_jp/athena/latest/ug/ddl-reference.html)

### 補足：AWS上にあるデータカタログにしかクエリを実行できないのか

結論を言うと外部のHive Metastoreと接続が可能なため、データカタログがなくてもデータソースを繋ぐことでAthenaクエリを実行できます。

[Using Athena Data Connector for External Hive Metastore - 参考](https://docs.aws.amazon.com/athena/latest/ug/connect-to-data-source-hive.html)

もしくはAWS Lambda で動作するコネクタを利用して実行できる
`Amazon Athena Federated Query`も利用できます。

[aws-athena-query-federation - GitHub](https://github.com/awslabs/aws-athena-query-federation)

## AthenaでETLを実行する

ここまで読んですでにお気づきの方が多いかと思いますが、分析サービスという肩書きを持ちながら
使いようによってはAthenaによるETLも可能です。

データを参照するだけでなく参照した結果をデータとして保存できる。これをCreate Table As Select、いわゆるCTAS呼びます。

つまり、`任意のSQLで実行して結果をS3に保存できる`ということになります。

## パフォーマンスチューニングとコスト最適化

ここまででデータの取り出し方やそれらを加工して保存する方法を知りました。オンデマンドで利用する場合においてはスキャンしたサイズで料金が決まります。
つまりはどれだけスキャンしたサイズを落とせたかでコストを削減できます。

少しだけ削減方法についてみていきましょう。

### クエリの最適化

この記事を書いている私は`必要なカラムだけを読みこむ`くらいしか意識していませんが
動作が遅いなどありましたら、試してみると良いかもしれません。

- ORDER BY を最適化する
    - LIMIT 句をつけることで、ORDER BY の負荷を軽減
- JOIN を最適化する
    - 結合の際には、大きなテーブルを左側に、小さなテーブルを右にする
- GROUP BY を最適化する
    - 複数カラムを指定する場合には、カーディナリティの高いカラムを前に持ってくる
- LIKE 演算子を最適化する
    - クエリ内で複数の LIKE 演算子を使う場合には、RegEx におきかえた方が高速になる
- 近似関数を使う
    - 多少の誤差を許容できるなら、COUNT DISTINCT でなく APPROX_DISTINCT() を使用
- 必要なカラムだけを読みこむ
    - できるだけ * を使わず、必要なカラムだけ

### パーティションを作成する

パーティションを作らない検索の場合は検索できる全てのデータを検索してからデータを取り出す流れになります。
つまりは実際の検索には不要なデータまで検索するため、スキャン量が増えてしまい、必要以上に料金がかかってしまいます。
そこでパーティションキーを作成して必要なデータだけをスキャンするようにします。

### 保存形式をParquetにする

`パーティションを作成する`理由と同じですが、データ容量を抑えるためにスキャン対象のデータを圧縮します。加えてParquet形式に保存します。Parquet形式にすることで行指向から列指向の検索が可能となり、検索時間を短縮できます。

## Athenaを外部から実行する方法（一部）

最後にAthenaはマネジメントコンソール以外からも実行できます。
ここでは一部を紹介します。

- AWS CLI
- AWS SDK
- AWS Step Functions
- 対応しているBIツール（Athenaを参照する）
    - Redash
    - Looker

## まとめ

S3にクエリを実行できるAmazon Athenaについて見ていきました。
データカタログの作成にAWS Glue DataCatalogが必要となるため、Amazon Athena以外の知識も必要となるところがポイントとなります。

また、CREATE TABLEを使うことで`ETLのような処理をSQLで実行できる`というところはAmazon Athenaの魅力的なポイントだと思います。

他、パフォーマンスチューニングなど細かいところまでやっていくとコストを下げながらS3へのデータ検索ができるので困っている人は検討してみると良いかもしれません。

## おわり