Amazon Athenaでビューを作成できますか? ユーザーインターフェイスを使用してビューを作成する方法の概要を示します。
プログラムでAWS Athena Viewを作成したいのですが、理想的にはTerraform(CloudFormationを呼び出す)を使用します。
私はここで概説されている手順に従いました: https://ujjwalbhardwaj.me/post/create-virtual-views-with-aws-glue-and-query-them-using-athena しかし、私は遭遇しましたビューがすぐに古くなるというこの問題。
...._view' is stale; it must be re-created.
Terraformコードは次のようになります。
resource "aws_glue_catalog_table" "Adobe_session_view" {
database_name = "${var.database_name}"
name = "session_view"
table_type = "VIRTUAL_VIEW"
view_original_text = "/* Presto View: ${base64encode(data.template_file.query_file.rendered)} */"
view_expanded_text = "/* Presto View */"
parameters = {
presto_view = "true"
comment = "Presto View"
}
storage_descriptor {
ser_de_info {
name = "ParquetHiveSerDe"
serialization_library = "org.Apache.hadoop.Hive.ql.io.parquet.serde.ParquetHiveSerDe"
}
columns { name = "first_column" type = "string" }
columns { name = "second_column" type = "int" }
...
columns { name = "nth_column" type = "string" }
}
私が喜んで使用する代替手段はAWS CLIですが、aws athena [option]
には、このオプションはありません。
私はもう試した:
あなたが示唆したように、AWS CLIでstart-query-execution
を使用してプログラムでAthenaビューを作成することは間違いなく可能です。ご指摘のとおり、ファイルをチェックする必要がない場合でも、結果のS3の場所を指定する必要があります(Athenaは何らかの理由で空のtxtファイルをその場所に配置します)。
次に例を示します。
$ aws athena start-query-execution --query-string "create view my_view as select * from my_table" --result-configuration "OutputLocation=s3://my-bucket/tmp" --query-execution-context "Database=my_database"
{
"QueryExecutionId": "1744ed2b-e111-4a91-80ea-bcb1eb1c9c25"
}
ワークグループを作成し、場所をそこに設定することで、クライアントにバケットを指定させないようにすることができます。
get-query-execution
コマンドを使用して、ビューの作成が成功したかどうかを確認できます。
$ aws --region athena get-query-execution --query-execution-id bedf3eba-55b0-42de-9a7f-7c0ba71c6d9b
{
"QueryExecution": {
"QueryExecutionId": "1744ed2b-e111-4a91-80ea-bcb1eb1c9c25",
"Query": "create view my_view as select * from my_table",
"StatementType": "DDL",
"ResultConfiguration": {
"OutputLocation": "s3://my-bucket/tmp/1744ed2b-e111-4a91-80ea-bcb1eb1c9c25.txt"
},
"Status": {
"State": "SUCCEEDED",
"SubmissionDateTime": 1558744806.679,
"CompletionDateTime": 1558744807.312
},
"Statistics": {
"EngineExecutionTimeInMillis": 548,
"DataScannedInBytes": 0
},
"WorkGroup": "primary"
}
}
Athenaでプログラムによってビューを作成することは文書化されておらず、サポートもされていませんが、可能です。 StartQueryExecution
を使用してビューを作成すると、舞台裏で何が起きるかは、AthenaがPrestoにビューを作成させ、Prestoの内部表現を抽出してGlueカタログに配置することです。
古さの問題は通常、Prestoメタデータの列とGlueメタデータが同期していないことに起因します。 Athenaビューには、ビューの3つの説明が実際に含まれています。ビューSQL、Glue形式の列とその型、Presto形式の列と型です。これらのいずれかが同期しなくなった場合、「…は古くなっています。再作成する必要があります」と表示されます。エラー。
これらは、Athenaビューとして機能するための接着テーブルの要件です。
TableType
は_VIRTUAL_VIEW
_でなければなりませんParameters
には_presto_view: true
_が含まれている必要がありますTableInput.ViewOriginalText
_には、エンコードされたPrestoビューが含まれている必要があります(以下を参照)StorageDescriptor.SerdeInfo
_は空のマップでなければなりませんStorageDescriptor.Columns
_には、ビューが定義するすべての列とその型が含まれている必要がありますトリッキーな部分は、エンコードされたPrestoビューです。その構造は次のコードによって作成されます: https://github.com/prestosql/presto/blob/27a1b0e304be841055b461e2c00490dae4e30a4e/presto-Hive/src/main/Java/io/prestosql/plugin/Hive /HiveUtil.Java#L597-L600 、そしてこれは多かれ少なかれそれがすることです:
/* Presto View:
_を追加します(_:
_の後にスペースを入れます)*/
_を追加します(_*
_の前にスペースあり)ビューを記述するJSONは次のようになります。
catalog
プロパティは、値awsdatacatalog
を持つ必要があります。schema
プロパティ(つまり、周囲の接着構造のDatabaseName
プロパティと一致する必要があります。name
およびtype
の列のリストoriginalSql
プロパティ(_CREATE VIEW …
_を含まず、_SELECT …
_または_WITH …
_で始まる必要があります)次に例を示します。
_{
"catalog": "awsdatacatalog",
"schema": "some_database",
"columns": [
{"name": "col1", "type": "varchar"},
{"name": "col2", "type": "bigint"}
],
"originalSql": "SELECT col1, col2 FROM some_other_table"
}
_
ここでの注意点の1つは、列のタイプがGlueの名前とほぼ同じであるが完全ではないことです。 Athena/Glueにstring
がある場合、このJSONの値はvarchar
でなければなりません。 Athena/Glueが_array<string>
_を使用する場合、このJSONの値はarray(varchar)
である必要があり、_struct<foo:int>
_はrow(foo int)
になります。
これはかなり厄介で、すべてをまとめるには、いくらかいじってテストする必要があります。これを機能させる最も簡単な方法は、いくつかのビューを作成してデコードし、上記の手順を逆に実行してそれらがどのように見えるかを確認してから、自分で試してみることです。
上記のTerraform 0.12+構文の例を更新し、ファイルシステムからのビュークエリの読み取りを追加します。
resource "null_resource" "athena_views" {
for_each = {
for filename in fileset("${path.module}/athenaviews/", "**"):
replace(filename,"/","_") => file("${path.module}/athenaviews/${filename}")
}
provisioner "local-exec" {
command = <<EOF
aws athena start-query-execution \
--output json \
--query-string CREATE OR REPLACE VIEW ${each.key} AS ${each.value} \
--query-execution-context "Database=${var.athena_database}" \
--result-configuration "OutputLocation=s3://${aws_s3_bucket.my-bucket.bucket}"
EOF
}
provisioner "local-exec" {
when = "destroy"
command = <<EOF
aws athena start-query-execution \
--output json \
--query-string DROP VIEW IF EXISTS ${each.key} \
--query-execution-context "Database=${var.athena_database}" \
--result-configuration "OutputLocation=s3://${aws_s3_bucket.my-bucket.bucket}"
EOF
}
}
when= "destroy"
ブロックにも注意して、スタックが破棄されたときにビューが確実に削除されるようにしてください。
SELECTクエリを使用してテキストファイルをモジュールパスの下のディレクトリ(この例ではathenaview /)に配置すると、ファイルが取得されてビューが作成されます。これにより、subfolder_filename
という名前のビューが作成され、ファイルが削除されるとビューが破棄されます。
Theoの回答への追加:base64エンコードされたJSONファイルでは、cloumn属性を定義するときに「string」タイプは無効です。この時点では常に "varchar"と記述してください。
編集:「int」も「integer」として宣言する必要があります!
私はTheoのソリューションを使用し、AWSクラウド形成テンプレートを使用して機能しました。
ちょっとしたヒントを追加したかったので、デバッグの時間を節約できます。まだコメントする権利がないので、コメントとしてこれを書いていません。これをTheoの回答のコメントセクションにコピーして貼り付けてください。
JD D
とTheo
による回答に追加し、それらのソリューションを使用して、Teraformを介してAWS Cliを呼び出す方法を以下に示しました。
resource "null_resource" "athena_view" {
provisioner "local-exec" {
command = <<EOF
aws sts assume-role \
--output json \
--region my_region \
--role-arn arn:aws:iam::${var.account_number}:role/my_role \
--role-session-name create_my_view > /tmp/credentials.json
export AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' /tmp/credentials.json)
export AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' /tmp/credentials.json)
export AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' /tmp/credentials.json)
aws athena start-query-execution \
--output json \
--region my_region \
--query-string "CREATE OR REPLACE VIEW my_view AS SELECT * FROM my_table \
--query-execution-context "Database=${var.database_name}" \
--result-configuration "OutputLocation=s3://${aws_s3_bucket.my-bucket.bucket}"
EOF
}
}
null_resource...を使用して、特定のリソースに直接関連付けられていないプロビジョナーを実行します。
aws sts assume-role
の結果はJSONとして/tmp/credentials.json
に出力されます。
jq は、 aws sts assume-role の出力から必要なフィールドを解析するために使用されます。
aws athena start-query-execution は、定義された環境変数で指定されたロールの下で実行できます。
--result-configuration "OutputLocation=s3://....
の代わりに--work-group
を指定できます。これはstart-query-execution
の別個のフラグであり、--result-configuration
文字列の一部ではないことに注意してください。
以前の回答に基づいて、ソースファイルが変更された場合にのみクエリを実行する例を次に示します。また、SQLクエリをコマンドに貼り付ける代わりに、file://
アダプタをAWS CLIコマンドに渡します。
resource "null_resource" "views" {
for_each = {
for filename in fileset("${var.sql_files_dir}/", "**/*.sql") :
replace(replace(filename, "/", "_"), ".sql", "") => "${var.sql_files_dir}/${filename}"
}
triggers = {
md5 = filemd5(each.value)
# External references from destroy provisioners are not allowed -
# they may only reference attributes of the related resource.
database_name = var.database_name
s3_bucket_query_output = var.s3_bucket_query_output
}
provisioner "local-exec" {
command = <<EOF
aws athena start-query-execution \
--output json \
--query-string file://${each.value} \
--query-execution-context "Database=${var.database_name}" \
--result-configuration "OutputLocation=s3://${var.s3_bucket_query_output}"
EOF
}
provisioner "local-exec" {
when = destroy
command = <<EOF
aws athena start-query-execution \
--output json \
--query-string 'DROP VIEW IF EXISTS ${each.key}' \
--query-execution-context "Database=${self.triggers.database_name}" \
--result-configuration "OutputLocation=s3://${self.triggers.s3_bucket_query_output}"
EOF
}
}
Destroyを正しく機能させるには、filename-example.sql
はクエリに関連します:
CREATE OR REPLACE VIEW example AS ...