はじめに
QuickSightがCloudFormationで操作できるので、AthenaのテーブルをQuickSightで使うには、という内容を試してみました。
参考
構成図
語がたくさん出てきてわからなくなったので、図示してみました。
構築
環境構築にあたって、2つの部分に分けました。
- 共通部分
- 1回構築すればよい部分
- 個別部分N個に対し、1つでよい部分
- バケット
- データ格納
- 出力先
- Athenaワークグループ
- Glueデータベース
- バケット
- 個別部分
- 設定を変えて複数作成を想定する部分
- Athenaテーブル
- QuickSight DataSource
- QuickSight DataSet
- 設定を変えて複数作成を想定する部分
1.共通部分の構築
先の図のうち、以下の部分が最初に1回だけ構築する共通部分になります。
CloudFormationは以下。パラメータEnv
を別にすることで、複数の環境が作成できるはずです。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
Env:
Type: String
Resources:
RawDataBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub raw-data-${AWS::AccountId}-${AWS::Region}-${Env}
BucketEncryption:
ServerSideEncryptionConfiguration:
-
ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
BucketKeyEnabled: false
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
AthenaQueryResultBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub query-result-${AWS::AccountId}-${AWS::Region}-${Env}
BucketEncryption:
ServerSideEncryptionConfiguration:
-
ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
BucketKeyEnabled: false
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
-
Id: 'auto-delete'
Status: 'Enabled'
ExpirationInDays: 7
AthenaWorkGroup:
Type: AWS::Athena::WorkGroup
Properties:
Name: !Sub athena-work-group-${Env}
RecursiveDeleteOption: true
WorkGroupConfiguration:
ResultConfiguration:
OutputLocation: !Sub s3://${AthenaQueryResultBucket}/data
EncryptionConfiguration:
EncryptionOption: 'SSE_S3'
EnforceWorkGroupConfiguration: true
PublishCloudWatchMetricsEnabled: true
GlueDatabase:
Type: AWS::Glue::Database
Properties:
CatalogId: !Ref AWS::AccountId
DatabaseInput:
Name: !Sub glue-database-${Env}
Outputs:
RawDataBucket:
Value: !Ref RawDataBucket
Export:
Name: !Sub "${Env}-RawDataBucket-Name"
AthenaQueryResultBucket:
Value: !Ref RawDataBucket
Export:
Name: !Sub "${Env}-AthenaQueryResultBucket-Name"
AthenaWorkGroup:
Value: !Ref AthenaWorkGroup
Export:
Name: !Sub "${Env}-AthenaWorkGroup-Name"
GlueDatabase:
Value: !Ref GlueDatabase
Export:
Name: !Sub "${Env}-GlueDatabase-Name"
- RawDataBucket
- データ格納バケット
- S3のSSEを設定
- パブリックアクセスブロックはON
- AthenaQueryResultBucket
- Athenaの実行結果を格納するバケット
- S3のSSEを設定
- パブリックアクセスブロックはON
- 7日でファイルを自動削除
- AthenaWorkGroup
- 環境専用のAthenaのワークグループ
- 出力先はAthenaQueryResultBucket
- GlueDatabase
- 環境専用のAthenaテーブルを作成するデータベース
注意点ですが、Athenaワークグループ(AthenaWorkGroup)は、実行履歴があると削除時に以下のようなエラーになり、削除できませんでした。
"Invalid request provided: WorkGroup athena-work-group-xxxx is not empty (Service: Athena, Status Code: 400, Request ID: xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, Extended Request ID: null)"
そのため、以下の設定を入れています。
RecursiveDeleteOption: true
参考のページは以下です。
2.QuickSightからのアクセス許可を設定
作成したバケットの両方に対して、QuickSightからアクセス許可を追加します。
またAthenaにアクセスできるようにもします。
QuickSightの管理画面で設定できます。
出力先バケットの場合は、「Athena Workgroupの書き込みアクセス許可」にもチェックを入れてください。
このあたりの部分もIaC化するのであれば、QuickSightで使用するロールに、自作のロールを使用することができそうです。以下の情報が参考になるかと思います。
3.データを格納
バケットに、Athenaテーブルで読ませたいデータを置きます。
今回は以下のファイルを置きました、社名を揃える用マスタというイメージです。
source,destination
ANA,全日本空輸
全日空,全日本空輸
全日本空輸,全日本空輸
source,destination
JR東,東日本旅客鉄道株式会社
JR東日本,東日本旅客鉄道株式会社
東日本旅客鉄道株式会社,東日本旅客鉄道株式会社
4.個別部分
Athenaテーブルを作成して、QuickSightに読み込ませる部分です。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
Env:
Type: String
TableName:
Type: String
Description: Table name must not contain uppercase characters.
QuickSightAdminUser:
Type: String
Description: user must not be asterisk(*).
Resources:
# Athena Table
GlueTable:
Type: AWS::Glue::Table
Properties:
CatalogId: !Ref AWS::AccountId
DatabaseName:
Fn::ImportValue:
!Sub "${Env}-GlueDatabase-Name"
TableInput:
Name: !Ref TableName
TableType: EXTERNAL_TABLE
Parameters:
skip.header.line.count: 1
has_encrypted_data: false
serialization.encoding: utf-8
EXTERNAL: true
StorageDescriptor:
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Columns:
- Name: source
Type: string
- Name: destination
Type: string
InputFormat: org.apache.hadoop.mapred.TextInputFormat
Location:
Fn::Join:
- ''
- - 's3://'
- Fn::ImportValue: !Sub "${Env}-RawDataBucket-Name"
- '/data'
SerdeInfo:
Parameters:
field.delim: ","
serialization.format: ","
SerializationLibrary: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
# QuickSight DataSource
AthenaDataSource:
Type: AWS::QuickSight::DataSource
Properties:
AwsAccountId: !Ref AWS::AccountId
Name: !Sub "${Env}-Athena"
DataSourceId: !Sub "${Env}-Athena-Id"
Type: ATHENA
DataSourceParameters:
AthenaParameters:
WorkGroup:
Fn::ImportValue:
!Sub "${Env}-AthenaWorkGroup-Name"
Permissions:
- Actions:
- quicksight:UpdateDataSourcePermissions
- quicksight:DescribeDataSource
- quicksight:DescribeDataSourcePermissions
- quicksight:PassDataSource
- quicksight:UpdateDataSource
- quicksight:DeleteDataSource
Principal: !Sub arn:aws:quicksight:${AWS::Region}:${AWS::AccountId}:user/default/${QuickSightAdminUser}
# QuickSight DataSet
RepDataSet:
Type: AWS::QuickSight::DataSet
Properties:
AwsAccountId: !Ref AWS::AccountId
Name: !Sub "Select-${GlueTable}"
DataSetId: !Sub "Select-${GlueTable}-Id"
ImportMode: SPICE
PhysicalTableMap:
rep-physical:
RelationalTable:
DataSourceArn: !GetAtt AthenaDataSource.Arn
# Set Database Name
Schema:
Fn::ImportValue:
!Sub "${Env}-GlueDatabase-Name"
# Set Table Name
Name: !Ref GlueTable
InputColumns:
- Name: source
Type: STRING
- Name: destination
Type: STRING
Permissions:
- Actions:
- quicksight:UpdateDataSetPermissions
- quicksight:DescribeDataSet
- quicksight:DescribeDataSetPermissions
- quicksight:PassDataSet
- quicksight:DescribeIngestion
- quicksight:ListIngestions
- quicksight:UpdateDataSet
- quicksight:DeleteDataSet
- quicksight:CreateIngestion
- quicksight:CancelIngestion
Principal: !Sub arn:aws:quicksight:${AWS::Region}:${AWS::AccountId}:user/default/${QuickSightAdminUser}
- QuickSightAdminUser
- DataSourceやDataSetを操作するQuickSightのユーザを指定します
- "*"だと、エラーになってしまいました。
- GlueTable
- Athenaのテーブル定義
- Locationは、共通部分の出力を参照しています。
-
注意
-
ColumnsのTypeは小文字
- 大文字でも作成はされますが、DataSetを作成する箇所で問題になりました。
-
ColumnsのTypeは小文字
- AthenaDataSource
- AthenaのDataSourceの定義
- 共通部分で出力したワークグループを参照
- RepDataSet
- AthenaのDataSetの定義
- 無加工であればPhysicalTableMapだけで定義可能
- RelationalTable.Schemaには、(共通部分で出力した)データベースをセット
-
注意
-
RelationalTable.InputColumnsのTypeは大文字
- 小文字だとエラーになります
- (上で注意した)AthenaのColumnsのTypeを大文字にすると、以下のようなエラーになります。
-
RelationalTable.InputColumnsのTypeは大文字
An error has been thrown from the AWS Athena client. HIVE_METASTORE_ERROR: Error: type expected at the position 0 of 'STRING' but 'STRING' is found.
作成に成功すると、QuickSight上でデータセットが作成され、置いたCSVが確認できます。
失敗談:削除時のやらかしについて
削除する際に、バケットを削除したあとにQuickSightのアクセス許可を外そうとすると、以下のようなちぐはぐな状態になっていました。
- QuickSightの管理画面ではアクセス許可の情報が表示されない
- IAMポリシーではアクセス許可が設定されている
このポリシーをQuickSight管理画面からではなく、直接修正するとQuickSightでは「外部で変更されたため、QuickSightからは編集できません」となり、以降QuickSightからはその部分の設定ができませんでした。
該当のポリシーを削除すれば、再度QuickSightから編集できます。ただし、削除前にどこのバケットに許可していたのかを控えておき、再度設定画面からチェックを入れる羽目になりました。
なので削除時は、操作の手順を正確に逆から行ってください。
おわりに
今回はAthenaを作って、それをQuickSightから読み込ませることを(おおよそ)IaC化しました。
今までQuickSightはGUIでしかできないと思っていましたが、IaC化で標準化が簡単に出来るようになれば、利用シーンが増えるのではないでしょうか。