Amazon Athenaのテーブルを可視化/分析するAmazon QuickSightをTerraformで自動構築する

# はじめに
Amazon QuickSightは、様々なデータソースの情報を可視化・分析するためのAWSフルマネージドなBIサービスだ。
複雑な設定が不要で、お手軽にデータ分析が開始できて、使いこなせれば非常に有用なツールになるだろう。

今回は、Amazon S3に格納されているNginxのJSON形式ログをAmazon Athenaで構造化したテーブルをAmazon QuickSightに取り込んで可視化する部分を、Terraformで構築してみる。

Nginxのログを取り込むためのAmazon Athenaの作成方法は、以下の過去記事を参照していただきたい。

https://qiita.com/neruneruo/items/b3256c0b30835e4f26a4

必要になる前提知識は以下の通り。

- Terraformの基礎的な知識
- Amazon Athenaの基礎的な知識
- Amazon QuickSightのマネージメントコンソールでの簡単な使い方

なお、Amazon QuickSightには、Standard EditionとEnterprise Editionの料金プランがあるが、今回の記事ではStandard Editionを利用する。

# Amazon QuickSightのアクティベーション
まず、アカウントレベルでのアクティベーションを行っておく。
これは既にアクティベーション済みであれば不要だ。

アカウント名と通知用メールアドレスには任意の値を設定しよう。

```HCL
resource "aws_quicksight_account_subscription" "example" {
  account_name          = "[アカウント名]"
  authentication_method = "IAM_ONLY"
  edition               = "STANDARD"
  notification_email    = "[通知用メールアドレス]"
}
```

# データソースの設定
Amazon QuickSightでは、データ構造として、データソース⊃データセットという包含関係でデータ定義をする。
データソースは、具体的に何のリソースから情報を持ってくる定義、データセットはその中で取り扱うデータを定義だと思っておけば良い。

```data_source_id```はその名の通りデータを一意に識別するための情報、```name```はコンソール等で表示される名前である。

今回、Amazon Athenaをデータソースとするため、```parameters```でワークグループの情報を渡しておく。

:::note warn
```permission```は、コンソール画面を扱うユーザが画面表示をするために許可するアクションを設定する。
たとえば、読み取り専用なユーザの画面に表示したくない場合は未設定にしておくと良いだろう。
:::

```HCL
resource "aws_quicksight_data_source" "athena_example" {
  aws_account_id = data.aws_caller_identity.current.account_id
  data_source_id = "athena_example"
  type           = "ATHENA"
  name           = "athena_example"

  parameters {
    athena {
      work_group = aws_athena_workgroup.example.name
    }
  }

  ssl_properties {
    disable_ssl = false
  }

  permission {
    principal = "arn:aws:quicksight:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user/default/[IAMユーザ名]"
    actions = [
      "quicksight:DeleteDataSource",
      "quicksight:DescribeDataSource",
      "quicksight:DescribeDataSourcePermissions",
      "quicksight:PassDataSource",
      "quicksight:UpdateDataSource",
      "quicksight:UpdateDataSourcePermissions"
    ]
  }
}
```

これで、以下のようにコンソール画面からデータソースが参照できるようになる。

![キャプチャ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/2374b9b6-8be9-1f61-4e0f-aebf0fd5fd30.png)

# データセットの設定
データセットでは、実際にAmazon Athenaのどの情報を扱うかを設定する。

今回は、高速化のためにデータをSPICEにインポートするため、```import_mode = "SPICE"```を設定している。

こちらも、データソース同様、```data_set_id```はデータセットの一意な識別子、```name```はマネージメントコンソール画面上等の表示名を意味する。

```physical_table_map```では、実際のAmazon Athenaのテーブルの情報を設定する。
カラム名は、この分析で必要になるものを抽出すれば良い。今回は、Amazon Athenaで設定している全カラムを持ってきている。

```logical_table_map```は、データ変換を設定する場合に利用する。
今回、Amazon Athena側のデータをすべてString型で設定してしまているが、分析をする都合上、日時の情報はDatetime型になっている方が望ましい(分析粒度を年・月・日・時・分・秒の精度で簡単に変更できる)ため、この時点で変換をかけた別のカラムを用意しておく。

:::note warn
Amazon QuickSightの```parseDate```関数で指定する日付フォーマットは、以下の参考サイトを参照。
Javaの```DateTimeFormat```クラスと同じ定義方法で、少しクセがあるので注意が必要だ。
特に、YYYYとyyyyを間違えると悲惨なことになるのはJavaあるあるのため、気を付けよう(大半の場合yyyyが正しい)
:::

https://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html

```permissions```ブロックも、データソース同様、これを設定していないとマネージメントコンソール画面に情報が表示されないため、必要なアクションを定義しておこう。

```HCL
resource "aws_quicksight_data_set" "athena_example" {
  data_set_id = "athena_example"
  name        = "athena_example"
  import_mode = "SPICE"

  physical_table_map {
    physical_table_map_id = "athena-example"
    relational_table {
      data_source_arn = aws_quicksight_data_source.athena_example.arn
      catalog         = "AwsDataCatalog"
      schema          = aws_athena_database.example.id
      name            = local.athena_table_name
      input_columns {
        name = "year"
        type = "STRING"
      }
      input_columns {
        name = "month"
        type = "STRING"
      }
      input_columns {
        name = "date"
        type = "STRING"
      }
      input_columns {
        name = "hour"
        type = "STRING"
      }
      input_columns {
        name = "time_local"
        type = "STRING"
      }
      input_columns {
        name = "request"
        type = "STRING"
      }
      input_columns {
        name = "remote_addr"
        type = "STRING"
      }
      input_columns {
        name = "ipaddr"
        type = "STRING"
      }
    }
  }
  logical_table_map {
    logical_table_map_id = "athena-example"
    alias                = local.athena_table_name
    source {
      physical_table_id = "athena-example"
    }
    data_transforms {
      create_columns_operation {
        columns {
          column_id   = "datetime"
          column_name = "datetime"
          expression   = "parseDate(time_local,\"dd/MMM/yyyy:kk:mm:ss +0000\")"
        }
      }
    }
  }

  permissions {
    principal = "arn:aws:quicksight:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user/default/[IAMユーザ名]"
    actions = [
      "quicksight:PassDataSet",
      "quicksight:DescribeIngestion",
      "quicksight:CreateIngestion",
      "quicksight:UpdateDataSet",
      "quicksight:DeleteDataSet",
      "quicksight:DescribeDataSet",
      "quicksight:CancelIngestion",
      "quicksight:DescribeDataSetPermissions",
      "quicksight:ListIngestions",
      "quicksight:UpdateDataSetPermissions",
    ]
  }
}
```

これをTerraformでApplyすると、以下のようにマネージメントコンソール画面に表示されるようになり、分析が開始できるようになる。

![キャプチャ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/5b33104e-2ee0-a940-ade9-b5959a996063.png)

![キャプチャ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/8e79a6eb-1820-3e68-568d-1c978a913ff1.png)

# 分析の開始
さて、残念ながら、Terraformでは分析に関するリソースも存在するが、Standard EditionではAPIの利用制限があり作成ができない。ここからは手作業だ。

マネージメントコンソールで上記の「分析で使用」ボタンを使っていろいろと遊んでみよう。

このような感じで、今回作成した```datetime```カラムによる粒度を変えての集計も簡単に切り替えられる。

![キャプチャ4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/1b1ed225-15da-3c62-e0c4-92a44f1e29df.png)

これで、お手軽なデータ分析の実現に近付いた！