woshidan's blog

そんなことよりコードにダイブ。

Amazon Athenaについて少し調べたのでメモ

まとまってないですが、忘れる前にメモ。

Amazon Athena とは

Amazon S3に入ったCSVJSONをAthena上で定義したスキーマに沿ってSQLで検索できるようにしてくれるクエリサービスです。

Athenaはサーバーレスのサービスで、利用するまでに最低限必要なステップは

  1. ファイルの入っているS3バケットの指定を含むスキーマの定義
  2. クエリを投げる

だけです。利用開始までにデータの抽出や変換、ロード(ETL)は必要なくなっています。ログ分析基盤などでやるようなアドホック分析に活用することができます。

スキーマというかテーブルの定義について

データベースはAthenaの管理画面の[Catalog Manager]などから作成可能です。 データベースごとにテーブルが100個まで作成できます*1

チュートリアルなどではテーブルをクエリエディタで定義していますが、この場合Hive互換のDDLを使って定義できます。

たとえばこういう形式のJSONが詰まったS3のバケットの中のファイルを検索させるためのテーブルを定義したい場合

{ "user_id": 12345, "data": { "imp_ids": [1,2,3,4,5] } }
{ "user_id": 23456, "data": { } }

このようにテーブルを定義することが可能です。

CREATE EXTERNAL TABLE IF NOT EXISTS array_tests (
  user_id String,
  data struct<imp_ids:array<INT>>
  )           
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://exmaple-woshidan-test/sample';

一度スキーマを定義した後にS3にあるファイルに変更を加えることなく後からスキーマを変更することも可能です。

ただし、Athenaで利用するS3のバケットの中のファイルはすべてスキーマの定義に沿った形式である必要があったり、同じバケットの中で違う形式のファイルを検索できるようにすることはできないので、ログ収集時に決めた部分を後から違うフォーマットで検索可能にすることは難しいです。

同じバケットの中でテーブルの定義にそぐわないフォーマットのファイルが見つかった場合は、そぐわない部分の列だけ空白の行が返ってきます。 アドホック分析なので途中から検索方法が違っても大丈夫、ということなのかもしれないです。

また、テーブルのパーティションについてはS3のバケットのパスに依存するので、こちらも後から変更することは難しい場合があります。

テーブルの変更はテーブルのドロップ -> 再作成という手順で行います。

RDBMSのテーブルと異なり、Athenaのスキーマ定義はS3の中のファイルを走査する際に利用されるメタデータのようなものなだけで、保存されているファイルのフォーマットがAthenaのスキーマ定義に影響を受けることはありません。

データの検索

データの検索もSQLのように行うことができます。 Athenaの検索の実行はPrestoを使って行われ、検索クエリを書く際はPrestoで利用できるキーワードの一部が利用可能となっています。

先ほどの例を用いていくらかクエリと実行結果を書いてみます。

SELECT * FROM mydatabase."array_tests" limit 10;
user_id data
1 12345 {imp_ids=[1, 2, 3, 4, 5]}
2 23456 {imp_ids=null}
SELECT * FROM mydatabase."array_tests" limit 10;
SELECT data.imp_ids FROM mydatabase."array_tests" WHERE user_id = '12345';
imp_ids
1 [1, 2, 3, 4, 5]

配列の検索は UNNESTCROSS JOIN を使って、配列の行を展開した行を生成することで可能なようです。パフォーマンスとかはあんまりわかってません。。

SELECT * FROM mydatabase."array_tests" cross join UNNEST (data.imp_ids) AS t (imp_id);
user_id data imp_id
12345 {imp_ids=[1, 2, 3, 4, 5]} 1
12345 {imp_ids=[1, 2, 3, 4, 5]} 2
12345 {imp_ids=[1, 2, 3, 4, 5]} 3
12345 {imp_ids=[1, 2, 3, 4, 5]} 4
12345 {imp_ids=[1, 2, 3, 4, 5]} 5
SELECT * FROM mydatabase."array_tests" cross join UNNEST (data.imp_ids) AS t (imp_id) WHERE imp_id = 3;
user_id data imp_id
12345 {imp_ids=[1, 2, 3, 4, 5]} 3

その他

Athenaでクエリを実行する先のS3に上げるJSONは1行

Athenaのクエリ実行先として指定するS3の中にあげるJSONは1行にminifyしておく必要があります。

Hive_CURSOR_ERROR: Row is not a valid JSON Object ... というエラーが出てよく見たら1行目の{あたりから怒られているような場合はこれが原因です。

参考

現場からは以上です。

*1:このあたりの制限は上限緩和申請が可能