データ活用基盤を作ってみたその１１（構築・データ活用-Athena）

# はじめに
こんにちは。NTTデータ先端技術の亀井（@kamein）です。
本記事はデータ活用基盤を作ってみた連載記事のその１１(構築・データ活用-Athena)です。本シリーズの取り組みの内容については[その１(構成シナリオ)](https://qiita.com/kamein/items/81df29ef9d32bf0a0810)をご覧ください。
今回のPJではデータ活用を蓄積領域(S3)のデータ閲覧としており、Athenaで実現します。本記事では、Athenaの設定手順や利用手順についてご紹介します。

# 目次
+ 今回のPJにおけるデータ活用の範囲
+ Athenaについて
+ 実装内容
    + ポリシー付与
    + AWS CLIインストール
    + ネットワーク穴あけ
+ 利用手順
+ 振り返り
+ 最後に

# 今回のPJにおけるデータ活用の範囲
今回のデータ活用におけるデータ活用はAI,BIのような使い方ではなく、データ連携の用途です。
蓄積領域(S3)に格納されたデータを既存システム側扱いのサーバ(EC2)からCliベースでデータを閲覧を目指しており、Athenaを使用します。
環境構成図の赤枠の範囲の機能実装ですが、既存システム側のEC2は作成済み環境を利用しており、今回のPJ範囲内の蓄積環境のS3とIAMロールはそれぞれの章で説明するため、本記事ではその他のAthena利用に向けて必要な設定や利用手順をご紹介します。

# Athenaについて
Athenaについてご紹介いたします。AthenaはS3に保存されたデータ(CSV,JSON,Apache Parquet等)をSQL形式で簡単にクエリができるサーバーレスのサービスです。
また、S3からDBにデータを移したり、Redshiftのクラスター起動したり等の面倒な工程を踏まずに直接S3参照できるため、アドホック分析に向いています。
Athenaには様々な方法でアクセスでき、AWSコンソール、API、JDBC、AWS CLI等で利用できます。
ただし、Glue Data Catalogに保存されているメタデータ(表名や列名等)を使用してSQLを作文・実行するため、Athenaを利用する前にGlue Data Catalogに分析対象データの登録が必須となります。
Athenaの詳細情報につきましては、[公式情報](https://docs.aws.amazon.com/ja_jp/athena/latest/ug/what-is.html)をご確認ください。

# 実装内容
今回のPJでは、「既存システムからCLIベースでアクセスできること」としていたため、次の手順で環境構築することを考えました。
1. データ活用者ロール（※ 詳細は[その７(構築・IAM)](https://qiita.com/fujitak-intellilink/items/4c4d5b62dac2d7b4d39f)参照)を使用できるポリシーを作成し、既存システム側のEC2に付与する
2. 既存システム上にAWS CLIをインストールして[aws athena](https://docs.aws.amazon.com/cli/latest/reference/athena/)が利用可能な状態にする
3. ネットワーク穴あけを行い疎通可能な状態にする
※ Glue Crawlerを使用してGlud Data Catalogにメタデータ自動登録実装済み

## ポリシー作成
データ活用者ロールを使用できるポリシーを作成し、EC2にアタッチしているロールに含めました。

※ 作成したjsonポリシー例
```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "sts:AssumeRole",
			"Resource": "arn:aws:iam::<アカウントID>:role/biwa-prod-iam-role-analyst-001" 
		}
	]
}
```

## AWS CLIインストール
通常は、公式ドキュメント[Get started with the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)に沿ってインストールする必要があります。
しかし、今回は既存システム側の対象サーバ(EC2)で使用しているのマシンイメージはAmazon Linuxでした。Amazon LinuxではAWS関連サービスで利用できるツール類は予めインストールされているため、本手順はスキップとしました。
※ 簡単なAWS検証作業でEC2を利用する場合には、この辺のセットアップ作業を省略できるのでAmazonLinuxの利用をお勧めします。

## ネットワーク穴あけ
今回は図に示すように3つのAWSサービスにアクセスするために各サービスに対応するVPCエンドポイントを構成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532829/548853a3-739d-e4a4-1513-1497f6b6a64a.png)

+ STS用エンドポイント
    + aws stsコマンドを使用してデータ活用者ロールを使用できるようにするために穴あけ
    + VPCエンドポイント作成時にcom.amazonaws.ap-northeast-1.stsサービスを指定する

+ Athena用エンドポイント
    + aws athenaコマンドを使用してAtenaでクエリが投げられるようにするために穴あけ
    + VPCエンドポイント作成時にcom.amazonaws.ap-northeast-1.athenaサービス名を指定する

+ S3用エンドポイント
    + aws s3コマンドを使用してS3内の状況を確認できるようにするために穴あけ
    + VPCエンドポイント作成時にcom.amazonaws.ap-northeast-1.s3サービスを指定する

※ それぞれのVPCエンドポイントに適用するセキュリティグループはEC2からのインバウンド方向の通信許可設定を加えます。

※ 今回の要件で追加した内容のみ記載しております。作業端末からEC2までのアクセスにはAWS Session Manager(SSM)を使用しておりますが、この図上では省略しております。


# 利用手順
構築後は試験工程で動作確認しました。ここでは参考情報としてAtenaのクエリを投げるまでにどのように手順が必要かをご紹介します。

1.データ活用者ロールの使用
```
$ aws sts assume-role --role-arn arn:aws:iam::<アカウントID>:role/<データ活用者ロール名> --duration-seconds 900 --role-session-name ssm-user --profile default --endpoint-url https://sts.ap-northeast-1.amazonaws.com

## ※ secret_access_key/session_token/access_key_idの出力結果をコピーする

$ export AWS_ACCESS_KEY_ID = <access_key_idの出力結果を貼り付け>
$ export AWS_SECRET_ACCESS_KEY= <secret_access_keyの出力結果を貼り付け>
$ export AWS_SESSION_TOKEN= <session_tokenの出力結果を貼り付け>

$ aws sts get-caller-identity --endpoint-url https://sts.ap-northeast-1.amazonaws.com
```

2.S3でバケット見れること確認
```
aws s3 ls
```

3.athenaでクエリを投げる
```
sh-4.2$ aws athena start-query-execution \
> --query-string "SELECT * FROM biwa_prod_s3_bucket_datastorage_002 limit 10;" \
> --query-execution-context Database=biwa-prod-glue-catalogdatabase-analytics-001 \
> --result-configuration OutputLocation=s3://biwa-prod-s3-bucket-athena-001/athena-result/

## ※ QueryExecutionIdの出力結果をコピーする

sh-4.2$ aws athena get-query-results --query-execution-id <QueryExecutionIdの出力結果を貼り付け>
```
※ 「biwa_prod_s3_bucket_datastorage_002」と「biwa-prod-glue-catalogdatabase-analytics-001」は、[その１０]()でデータカタログに登録した情報を指定します

```
## 参考までにget-query-resultsの出力結果を表示します
{
    "UpdateCount": 0,
    "ResultSet": {
        "Rows": [
            {
                "Data": [
                    {
                        "VarCharValue": "jis_code"
                    },
                    {
                        "VarCharValue": "old_postal_code"
                    },
                    {
                        "VarCharValue": "postal_code"
                    },
                    {
                        "VarCharValue": "prefecture_kana"
                    },
                    {
                        "VarCharValue": "city_kana"
                    },
                    {
                        "VarCharValue": "town_kana"
                    },
                    {
                        "VarCharValue": "prefecture_kanji"
                    },
                    {
                        "VarCharValue": "city_kanji"
                    },
                    {
                        "VarCharValue": "town_kanji"
                    },
                    {
                        "VarCharValue": "multiple_towns_flag"
                    },
                    {
                        "VarCharValue": "has_subdivision_flag"
                    },
                    {
                        "VarCharValue": "has_district_flag"
                    },
                    {
                        "VarCharValue": "multiple_areas_flag"
                    },
                    {
                        "VarCharValue": "update_status"
                    },
                    {
                        "VarCharValue": "change_reason"
                    }
                ]
            },
            {
                "Data": [
                    {
                        "VarCharValue": "1101"
                    },
                    {
                        "VarCharValue": "60"
                    },
                    {
                        "VarCharValue": "600000"
                    },
                    {
                        "VarCharValue": "ﾎｯｶｲﾄﾞｳ"
                    },
                    {
                        "VarCharValue": "ｻｯﾎﾟﾛｼﾁｭｳｵｳｸ"
                    },
                    {
                        "VarCharValue": "ｲｶﾆｹｲｻｲｶﾞﾅｲﾊﾞｱｲ"
                    },
                    {
                        "VarCharValue": "北海道"
                    },
                    {
                        "VarCharValue": "札幌市中央区"
                    ～（中略）～
                    }
                ]
            }
        ],
        "ResultSetMetadata": {
            "ColumnInfo": [
                {
                    "Scale": 0,
                    "Name": "jis_code",
                    "Nullable": "UNKNOWN",
                    "TableName": "",
                    "Precision": 19,
                    "Label": "change_reason",
                    "CaseSensitive": false,
                    "SchemaName": "",
                    "Type": "bigint",
                    "CatalogName": "hive"
                }
            ]
        }
    }
}
```

# 振り返り
無事にAthenaでクエリを実行・表示することができました！
RDBMS等のデータベースに入れ直すことなくAthenaを使えばオブジェクトストレージのS3に直接参照できて良いですね。Athenaを使用するまでの手間もCrawler設定、ネットワーク穴あけ、IAM権限設定ぐらいで簡単に利用できるので導入しやすいです。

# 最後に
S3データを簡単に閲覧できるのでAthenaはスモールスタートに適したサービスだと考えます。
よくあるBIツールのtableauやAIツールのdataiku等でもAthenaをデータソースとして利用できるため、本格的なデータ分析にも移行しやすいです。
機会がありましたら一度はAthenaに触れておくことをお勧めいたします。
次の記事は、データ活用基盤を作ってみた[その１２](https://qiita.com/shiraki_ils/items/430f6e3ee71fe14f7d87)です。
最後までお読み頂きありがとうございました。