Can you create views in 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]
对此不提供任何选择。
我尝试过:
答案 0 :(得分:3)
在Athena中以编程方式创建视图的记录和支持不受支持,但可以实现。使用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:
(注意尾随空格)*/
(注意初始空格)描述视图的JSON如下所示:
catalog
属性,其值必须为awsdatacatalog
。schema
属性必须是创建视图的数据库的名称(即它必须与周围的Glue结构的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"
}
这里需要说明的是,列的类型几乎与Glue中的名称相同,但并不完全相同。如果Athena / Glue将具有string
,则此JSON中的值必须为varchar
。如果Athena / Glue使用array<string>
,则此JSON中的值必须为array(string)
,并且struct<foo:int>
变为struct(foo int)
。
这很混乱,将它们放在一起需要一些摆弄和测试。使它正常工作的最简单方法是创建一些视图并向后解码上面的指令以查看它们的外观,然后尝试自己做。
答案 1 :(得分:2)
为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
的视图,并在删除文件后销毁它们。
答案 2 :(得分:2)
根据先前的回答,这是一个仅在源文件已更改的情况下执行查询的示例。此外,它使用file://
适配器将SQL查询粘贴到命令中,而不是将SQL查询粘贴到命令中。
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
}
}
要使销毁工作正常进行,请使用与文件名完全相同的文件名-example.sql
与查询相关:
CREATE OR REPLACE VIEW example AS ...
答案 3 :(得分:1)
正如您所建议的那样,绝对有可能使用package game;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class runner extends JPanel {
static MyKeyListener list;
static player play;
static grid gameGrid;
static int size = 600;
public runner() {
MyKeyListener listener = new MyKeyListener(this);
player one = new player(5, 4);
grid Grid = new grid(10, 10, size, one);
play = one;
gameGrid = Grid;
list = listener;
this.addKeyListener(listener);
setFocusable(true);
}
public static void main(String[] args) {
runner runn = new runner();
JFrame frame = new JFrame("game");
int frameSize = size + (size / 2);
frame.setSize(size, size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(runn);
frame.addKeyListener(list);
boolean isRunning = true;
while (isRunning) {
drawingComponent DC = gameGrid.update();
if (list.getDir() == 1) {
gameGrid.moveUp(play, play.getX(), play.getY());
list.setDir(0);
}
if (list.getDir() == 2) {
gameGrid.moveDown(play, play.getX(), play.getY());
list.setDir(0);
}
if (list.getDir() == 3) {
gameGrid.moveLeft(play, play.getX(), play.getY());
list.setDir(0);
}
if (list.getDir() == 4) {
gameGrid.moveRight(play, play.getX(), play.getY());
list.setDir(0);
}
frame.add(DC);
frame.revalidate();
frame.repaint();
}
}
public player getPlayer() {
return play;
}
}
通过AWS CLI以编程方式创建Athena视图。正如您所指出的那样,这确实需要您为结果提供S3位置,即使您不需要检查文件(由于某些原因,Athena也会在该位置放置一个空的txt文件)。
这里是一个例子:
start-query-execution
您可以避免让客户端通过c reating a workgroup and setting the location there.
指定存储桶您可以使用$ 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
答案 4 :(得分:1)
Theo的回答:在base64编码的JSON文件中,定义cloumn属性时,“字符串”类型无效!始终在此时写“ varchar”。
edit:同样,必须将“ int”声明为“ integer”!
我采用了Theo的解决方案,并且使用了AWS Cloud Formation模板。
我只想添加一些提示,可以节省您的调试时间。我没有将其写为评论,因为我还没有发表评论的权利。随时将其复制并粘贴到Theo答案的评论部分。
答案 5 :(得分:0)
要添加JD D
和Theo
的答案以及它们的解决方案,我们在以下方面找到了如何通过terraform调用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
字符串的一部分。