DynamoDBのデータをAmazon Athenaでクエリ実行まで

## はじめに

DynamoDBのデータをAthenaで分析したい、という話です。
基本的には以下の記事の内容そのままですが、一部そのままだと使いにくい部分があるので補足しています。

[新機能 – Amazon DynamoDB テーブルデータを Amazon S3 のデータレイクにエクスポート。コードの記述は不要](https://aws.amazon.com/jp/blogs/news/new-export-amazon-dynamodb-table-data-to-data-lake-amazon-s3/)

## DynamoDBのデータをS3にエクスポートする

まず、DynamoDBのデータをS3に保存します。
Athenaから直接DynamoDBにつなぐ方法もありますが、DynamoDBのキャパシティを消費するので今回は候補から除外しました。
[Amazon Athena DynamoDB コネクタ](https://docs.aws.amazon.com/ja_jp/athena/latest/ug/athena-prebuilt-data-connectors-dynamodb.html)

今回対象とするデータは以下になります。
![Snag_47819f4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/582d96b4-8b04-b7dd-dc74-f7011af42370.png)

DynamoDBデータをS3に保存するためにはS3エクスポートの機能を使います。
「S3へのエクスポート」をクリックします。
![Snag_4799048.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/f567622e-80eb-5674-d63e-134feba2964f.png)

テーブルにPITRを有効化する必要があるため、「PITRの有効化」をクリックします。
![Snag_47a4d4e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/6bafe3e8-e8cd-d560-0e6c-4efe0d2318d0.png)

保存先のS3バケットを選択して「エクスポート」をクリックします。
![Snag_47b093c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/474adbe0-c01d-12cf-7748-af0b182c31b4.png)

エクスポート完了まで数分待ちます。(5~10分程度)
![Snag_47be93c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/b3359403-9e36-9e18-34a6-02aed89e7e37.png)

エクスポートが完了すると以下のような構成でS3にファイルが保存されます。
対象とするデータは「data/」に保存されます。
![Snag_47cc5b1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/81cf72bf-dd89-0522-7053-973a2508e98c.png)

## Athena分析用にGlueの設定を実施する

AWS Glueの「クローラ」を選択し、「クローラの追加」をクリックします。
![Snag_47f0466.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/ea96f8bf-fbd4-5759-3fbd-bf480c68bfbf.png)

クローラの名前を入力して、「次へ」をクリックします
![Snag_48dc7c2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/3b834838-83a9-8ce6-cfa2-512a6474ee21.png)

今回はクローラがテーブルを作成する構成のため、以下の画像の設定で「次へ」をクリックします。
![Snag_48e6598.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/20459591-79dd-628a-6c29-951b67927937.png)

データストアの追加では対象とするS3バケットを選択し、エクスクルードパターンには以下のように設定します。
![Snag_48fc16f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/6187ed50-7f24-4c96-0742-44ebb203f96f.png)

別のデータストアは追加しないので以下のようにします。
![Snag_490ca82.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/6bd6df23-680d-1d71-64cd-c57eab1c930c.png)

IAMロールは今回新規作成します。
![Snag_4915b49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/ff23fa00-b9cf-11e9-39e8-af7f2e560f86.png)

スケジュールは「オンデマンドで実行」とします。
![Snag_491d626.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/e4a4a78d-d0cb-e89e-cb64-0de128950569.png)

クローラの出力はデフォルトのままで「次へ」をクリックします。
![Snag_49296f5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/e7b77d33-a3b1-184c-6c59-7c9763dfadb6.png)

クローラができたら、選択して「クローラの実行」をクリックします。
![Snag_4939b17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/83b285b6-1a78-4dcc-b5e0-3a81666026ae.png)

## Athenaでデータを検索する

前述のクローラの実行でAthena側に一つ新規テーブルが作成されていると思います。
S3に出力されるデータ形式がDynamoDB JSONのため、クエリ形式は少し工夫する必要があります。
```
SELECT Item.Id.S as id, Item.name.S as name, Item.age.N FROM "default"."athena_sample_12345" where  limit 10;
```

![Snag_496a2d9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/9fe24f4d-6324-54ea-f6b5-8b35b6662aa0.png)

再度S3エクスポートを実施してS3には以下のようにデータが保存されているとします。
![Snag_4a20110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/d0be84c2-252c-0f57-b3c1-1fc8267c92bf.png)

データを検索すると同じデータが2セット確認できます。
![Snag_4a25971.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/a18d67db-d917-bcae-b15b-ddfcb9d6a277.png)

パーティションが設定されているので、partition_1で検索すると検索対象のデータ数が半分になっていることが確認できます。
※Athenaは検索対象のデータ量に応じて課金されるため、パーティションをうまく利用することで料金を押させることができます。
![Snag_4a33673.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/105a24eb-0334-8689-fac9-d0633120cea2.png)

## Step Functionsで自動化する

今回の一連の作業を自動化してみたいと思います。
一連の流れを整理すると以下になります。

* 対象のS3バケット内のデータを空にする
  * DB内のデータが重複してS3に保存されるのを避けるため
* DynamoDBのS3エクスポートでデータをS3に出力する
* Glueのクローラを実行する

今回の入力値としては以下のようになります。
複数テーブルに対応できるようにしてみました。
※今回は検証のため同じテーブルのデータを別のS3のディレクトリに出力するようにしています。
![Snag_4e7dfa9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/dfbc23ea-2385-e5c9-9f43-db4b71e7aaca.png)

最終的なステートマシンは以下のようになりました。
![Snag_4e4f87f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/0627d296-4df1-f9d0-ef60-361b8f31218c.png)

Athenaでデータ検索すると以下のようになります。
しっかりパーティションも設定されているのでテーブルデータごとの検索もできますね。
![Snag_4f5b691.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/fe181aaa-6a55-c722-113c-52f02fbe380e.png)

## まとめ

DynamoDBのテーブルをS3に保存してS3に保存されている他のデータを組み合わせて分析したい、というユースケースは結構あるかと思います。
今回はマネジメントサービスのみを使ってノーコードで実装してみました。
もちろん、Lambdaなどを作っても同じようなことはできるかと思いますが、ノーコードでの実装だとLambdaの実装になれていない人でも簡単に分析基盤を作れそう、というのは理解頂けたのかなと思います。