以编程方式创建AWS Athena视图

tjh*_*in1 6 aws-cloudformation aws-cli terraform amazon-athena terraform-provider-aws

您可以在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" }
}
Run Code Online (Sandbox Code Playgroud)

我很乐意使用的替代方法是AWS CLI,但是aws athena [option]对此没有任何选择。

我试过了:

  • 我无法为诸如CREATE或REPLACE VIEW之类的语句工作的create-named-query,因为这似乎不是此命令的预期用例。
  • start-query-execution要求输出位置,这表明它是用于查询数据并输出结果,而不是进行有状态的更改/创建。它似乎也与stop-query-execution配对。

JD *_*D D 12

正如您所建议的,绝对可以通过 AWS CLI 使用start-query-execution. 正如您所指出的,这确实需要您为结果提供 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"
}
Run Code Online (Sandbox Code Playgroud)

您可以通过创建工作组并在那里设置位置来避免让客户端指定存储桶

您可以使用该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"
    }
}

Run Code Online (Sandbox Code Playgroud)

  • 通过在我的 _work group_ 上设置 _Query 结果位置_,我能够用 `--work-group` 替换 `--result-configuration`。 (2认同)

小智 7

更新 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
  }
}
Run Code Online (Sandbox Code Playgroud)

还要注意然后when= "destroy"阻止以确保在您的堆栈被拆除时删除视图。

将带有 SELECT 查询的文本文件放在目录(在此示例中为 athenaview/ )下的模块路径下,它将拾取它们并创建视图。这将创建名为 的视图subfolder_filename,并在删除文件时销毁它们。


The*_*heo 6

没有文档记录在雅典娜中以编程方式创建视图,并且不受支持,但是可以实现。使用创建视图时,幕后发生的事情StartQueryExecution是Athena让Presto创建视图,然后提取Presto的内部表示并将其放入Glue目录中。

陈旧性问题通常来自Presto元数据中的列和Glue元数据不同步。Athena视图实际上包含对该视图的三个描述:视图SQL,Glue格式的列及其类型,以及Presto格式的列和类型。如果其中任何一个不同步,您将得到“…已陈旧;必须重新创建它”。错误。

这些是在胶水表上用作雅典娜视图的要求:

  • 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:(后面有一个空格:
  • 添加一个基本的64位编码的JSON字符串,该字符串包含视图SQL,列及其类型以及一些目录元数据(请参见下文)
  • 添加后缀*/(之前有一个空格*

描述视图的JSON如下所示:

  • 一个catalog必须具有的价值属性awsdatacatalog
  • schema属性,必须是在视图中创建(即,其必须在匹配数据库的名称DatabaseName周边胶结构的属性。
  • 列的列表,每个列都有一个nametype
  • 一个originalSql实际视图SQL财产(不包括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"
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是,列的类型几乎与Glue中的名称相同,但并不完全相同。如果Athena / Glue string在此JSON中的值必须为varchar。如果Athena / Glue使用array<string>此JSON中的值,则必须为array(varchar),并且struct<foo:int>变为row(foo int)

这很混乱,将它们放在一起需要一些摆弄和测试。使它正常工作的最简单方法是创建一些视图并向后解码上面的指令以查看它们的外观,然后尝试自己进行操作。

  • 令人惊讶的是,仍然没有更好的方法来处理这个问题。我想对视图的内容进行版本控制,然后将其放入 CF 模板中,但目前看来过于复杂。如果有一些技巧可以在 CF 模板中很好地完成此操作,我会很感兴趣,但我还没有找到任何东西。 (3认同)
  • 要补充一点:雅典娜中的struct列数据类型需要映射到Presto定义JSON中的row,例如Terraform / Glue定义中的type =“ struct &lt;col1:string&gt;”映射为“” type Presto视图定义中的“:” row(col1 varchar)“`。 (2认同)

Mac*_*ski 5

根据之前的答案,这里有一个示例,仅当源文件已更改时才执行查询。也不是将 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
  }
}
Run Code Online (Sandbox Code Playgroud)

为了使销毁工作正确,命名文件与文件名完全相同 -example.sql与查询相关:

CREATE OR REPLACE VIEW example AS ...
Run Code Online (Sandbox Code Playgroud)