はじめに
この記事は初めてAWS Athenaを利用するユーザーを対象にしております。
はじめてAWS Athenaを使う人のチュートリアルのようなものになれば幸いです。
AWS Athenaって何?
概要
簡単に言うと、AWSが提供するフルマネージドサービスで、S3にあるデータファイルに対してクエリを実行することの出来るサービスになります。
つまり、S3(オブジェクトストレージ)にデータ(csvやparquet)を配置してしまえば、それだけでそのデータの分析を始められることができます。フルマネージドサービスなのでサーバーの管理は不要ですし、データをRDBにインポートさせる手間も必要ありません。
料金
スキャンされたデータ 1 TB あたり 5USD (2019年7月13日 東京リージョン)
これのみです。クエリを実行した分だけ料金が発生します。
1ドル=107円換算で1GBあたり約0.522円ほどになります。
利点
これは私の所感になります。
- 使った分だけ請求されるので料金が安い!!
- クエリの実行が速い!!
- データを入手してからすぐに分析のフェーズに入れるのでとても楽。余計なことを考えなくて済むのは大きい。
実際に使ってみる
テーブルを作成する
では、実際に使ってみましょう。
まずS3にデータを配置します。今回は日本の人口推移データをs3://inu-is-dog/athena/c01.csvに配置しました。(都合上、csvのヘッダーを英語表記に変更いたしました。)
配置されるデータは構造体が同じならば同じキーに複数存在しても問題ありません。例えば、同じ構造体のc02.csvがs3://inu-is-dog/athena/c02.csvのように配置されていても大丈夫です。
データの詳細
出典:政府統計の総合窓口(e-Stat)(https://www.e-stat.go.jp/)
では、テーブルの作成を行なっていきます。今回はデフォルトで配置されている"default"のデータベースに"population_table"というテーブルを作成します。
以下のクエリを実行します。(使用用途に合わせてアレンジしてください)
CREATE EXTERNAL TABLE IF NOT EXISTS default.population_table (
code string,
prefecture string,
era_name string,
japanese_calender int,
year int,
comment string,
all_population bigint,
man_population bigint,
woman_population bigint
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES ( 'escapeChar'='\\', 'quoteChar'='\"', 'integerization.format' = ',', 'field.delim' = ',' )
LOCATION 's3://inu-is-dog/athena/'
TBLPROPERTIES ('has_encrypted_data'='false', 'skip.header.line.count'='1', 'serialization.encoding'='SJIS')
注意すべき点は以下になります。
- カラムの数とデータ型があっているのかどうか?
- S3のパスはあっているのか?(LOCATION)
- ヘッダーはあるのか?(TBLPROPERTIESのskip.header.line.count)
- 文字コードはあっているのか?(TBLPROPERTIESのserialization.encoding) ※デフォルトではutf8で読み込む。今回はSJIS
- 区切り文字やエスケープ文字はあっているか?(SERDEPROPERTIES)
無事、テーブルを作成することが出来ました。
クエリの実行
せっかくテーブルを作成したのでクエリを実行してみましょう。
今回は都道府県ごとの累計人口を表示するクエリを実行します。
クエリの実行のショートカットはMacなら「command + Enter」、Windowsなら「contorol + Enter」になります。
クエリの内容
SELECT prefecture, SUM(all_population) AS all_population
FROM default.population_table
GROUP BY 1
ORDER BY 2 DESC;
実行結果
クエリの結果をCSVでダウンロードしたい場合はこのアイコンをクリックしましょう。
AthenaはPresto SQLに準拠しているのでクエリの書き方で悩んだらPresto Sqlのリファレンスとか読むと解決することが多いです。
料金を節約する
データ圧縮
今回は単純なcsvファイルでしたが、圧縮ファイルでも同じようにクエリを実行することが出来ます。
なので今回のファイルc01.csvをc01.csv.gzに圧縮することでスキャンするデータ量を節約することが出来ます。
パーティション
Athenaのテーブルにはパーティションの機能が付いています。S3のプレフィックスをパーティションごとに切ることでスキャンするデータ量を節約できます。
具体的には、今回した人口のデータを年ごとに分割し、それぞれを適切なプレフィックスに配置します。
- s3://inu-is-dog/athena/year=1920/~~.csv
- s3://inu-is-dog/athena/year=1921/~~.csv
- s3://inu-is-dog/athena/year=1922/~~.csv
- ...
そしてテーブルを作成します。
CREATE EXTERNAL TABLE IF NOT EXISTS default.population_table (
code string,
prefecture string,
era_name string,
japanese_calender int,
year int,
comment string,
all_population bigint,
man_population bigint,
woman_population bigint
)
PARTITIONED BY (year int) <- 追加
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES ( 'escapeChar'='\\', 'quoteChar'='\"', 'integerization.format' = ',', 'field.delim' = ',' )
LOCATION 's3://inu-is-dog/athena/'
TBLPROPERTIES ('has_encrypted_data'='false', 'skip.header.line.count'='1', 'serialization.encoding'='SJIS')
これで年ごとにパーティションされたテーブルが出来ます。
この手法は常に全体のデータの集計をする場合は効果がありませんが、範囲を指定してデータを集計する時には効果を発揮します。
今回の場合だと例えば1970年代だけの人口の累計を把握したいとき、1970年から1979年のデータしかスキャンしないためその分Athenaで発生する料金を節約できます。
SELECT prefecture, SUM(all_population) AS all_population
FROM default.population_table
WHERE year BETWEEN 1970 AND 1979
GROUP BY 1
ORDER BY 2 DESC;
Parquetの採用
csvやtsvは行指向と呼ばれるデータ形式ですが、parquetと呼ばれる列指向のデータ形式を採用することで料金を節約できる可能性があります。
例えば、以下のクエリを実行するとしましょう。
SELECT code, prefecture
FROM default.population_table
このテーブルでスキャンされるファイルがcsvの場合全行をスキャンする必要があります。
一方、parquetの場合、codeとprefectureのカラムだけをスキャンするので無駄な他のカラムを読むことがありません。
おわりに
この記事がこれからAWS Athenaを使ってみたいという方のお力になれば幸いです。
今後、他の機能(CTASや、GlueとQuickSightの連携など)についても執筆できたらと思います。
CREATE TABLEについてはこちらをどうぞ