Core開発部Kです。S3に溜め込んでいるデータを集計して扱おうと思ったのですが、サイズが膨大なためRedshiftではコスト感が合わなく、結局EMRを利用して処理をして、結果のデータをS3に配置してAthenaを利用して読み込むという形になりました。その際に確認した、配置するデータの形式やパーティションを区切っての利用方法等をまとめておきたいと思います。
AWS Athenaとは
S3内のデータを標準SQLを利用して分析する事ができるサービスです。サーバーレスなので、実行したクエリに対してのみ料金が発生します。類似のサービスとしてはGoogle Cloud Platform (GCP) のBigQueryがあります。
データ形式
Athenaで利用できるデータ形式には CSV, JSON, ORC, Avro, Parquetといった様々なデータ形式がサポートされているのですが、今回はParquetというファイル形式を利用する事にしました。 Athenaの料金は読み込んだデータ量で決まってくるのですが、行指向のデータ(CSV,JSON)の場合にはファイル全体を読み込む必要があるのに対し、列指向のフォーマットの場合にはデータを列単位で読み込めるため、ファイル全体を読む必要がなく読み込むデータ量を削減でき、Athenaの使用料の削減に繋がるからです。 Athenaで読み込める列指向のデータ形式はParquet, ORCの2種類があったのですが、データを作成するにあたってPythonから出力しやすいParquetを使用する事にしました。 Pythonでは、Apache ArrowのPythonバインディングであるPyArrowを利用する事でParquet形式での出力が可能です。(20181220現在ORCフォーマットは読み込みのみしか出来ませんでした)
S3へのデータ配置
S3へファイルを置く際にはパーティションを意識してファイルを配置する必要があります。Athenaのテーブル定義をする際にパーティションに利用するキーを設定する事が出来ます。パーティションを設定する事で、検索時に読み込むS3のファイルを絞り込む事ができるため検索速度の向上と、読み込んだデータ量で料金が変わるAthenaではコストの節約が期待できます。 Athenaではパーティション分割にHiveを使用しているため、S3上にデータを配置する際にHive形式でS3上にファイルを配置する事で、容易にパーティション分割を行う事ができます。
Hive形式
テーブル定義を行う際にパーティションを分割するカラムを指定した上で、そのカラムについて <bucketname>/<tablename>/date=2018-12-21/data.parquet
の様にS3に配置するデータ内ではなく、 date=YYYY-MM-DD
の様な形で対象ファイルのディレクトリ構造内にカラムの情報を設定する事で、パーティション分割を行う事が可能です。データベースとテーブルの作成については後述します。
データ配置
S3にデータを配置します。今回確認用に配置するデータは下記の様な内容で作成したparquetのデータとなります。
ファイル名 | data1 | data2 |
---|---|---|
testdata1.parquet | 1〜10000000の連番 | 0 |
testdata2.parquet | 0 | 1〜10000000の連番 |
確認用に作成したbucket内には下記の様に配置しました
athena-test-201812 ─ test ┬ date=2018-12-20 ─ testdata1.parquet └ date=2018-12-21 ─ testdata2.parquet
データベースとテーブルの作成
Athenaを利用するにあたって、まずはAWS Glue上でデータベースとテーブルを追加します。
1) Glueからデータベースの追加を選択します
2) データベース名を設定してデータベースを追加します
3) データベースが追加されたら選択して情報を確認します
4) 作ったばかりのDBなのでテーブルが無いため追加します
5) テーブルの追加から手動でテーブルの追加を選択します
6) 追加する対象のデータベースを選択します
7) インクルードパスにデータを配置したディレクトリを設定します
8) 配置してあるデータのフォーマットを設定します
9) テーブルの列を追加していきます、パーティションに使用する列はパーティションキーにチェックを入れます
10) 列の追加が完了したら次へを選択します
11) テーブル定義を確認し問題なければテーブルを作成します
Athenaでの検索
Glueでデータベースとテーブルを作成すると、Athena上から該当のデータベースを選択する事でクエリでの検索が可能になります。
試しにいくつかクエリを投げて確認をしてみます。
全体から検索してみます。
select * from test;
1件も検索に引っかかりませんでした。
Athenaのパーティションが設定されていないため 対象ファイルを読み込めていない状態です。
パーティションは次のように確認します。
show partitions <tablename>
パーティションが無いことが確認できました。 パーティションを作成します。
msck repair table <tablename>
コマンドを実行することでHive形式で設定されているパーティションを自動的に読み込んでパーティションを作成してくれます。
パーティションが作成できたか、確認します。
show partitions <tablename>
パーティションが作成出来ていることを確認できました。 改めて全体を検索してみます。
select * from test;
スキャンしたデータ量は76.88MBとなっています。 出力された結果を確認したところ、ちゃんと全件(20000000件)の出力がされていました。 (ちなみに実行時間がかかっているのは、出力サイズが大きいためです。今回の結果は513MBでした。)
次はパーティションを指定して検索してみます。
select * from test where date=cast('2018-12-21' as date);
スキャンしたデータ量は38.44MBとなっています。 列指向のデータなので、更に列を指定して検索してみます。
select date2 from test where date=cast('2018-12-21' as date);
スキャンしたデータ量が38.55MBとなっています。 変わっていないように見えますが、もう一つの列について検索してみます。
select date1 from test where date=cast('2018-12-21' as date);
こちらはスキャンしたデータ量が0.2KBとなっています。 parquet形式は列でデータを圧縮するため 全てのデータが0であったdata1がかなりの圧縮率となっており データ量の内殆どがdata2によるものとなっていた事が判りました。
まとめ
簡単にではありますが、parquet形式でS3に置いたデータについて、Athenaから検索を行うための準備と方法についてまとめました。 膨大なデータに対して一度に必要な部分が限られるのであれば、Partitionを適切に区切る事でコストを抑えて素早く検索が出来るので、用途次第ではありますが、Athenaはとても使いやすいサービスと感じました。
参考:
データのパーティション分割 - Amazon Athena
Amazon Athena のパフォーマンスチューニング Tips トップ 10 | Amazon Web Services ブログ