【问题标题】:Querying S3 using Athena使用 Athena 查询 S3
【发布时间】:2020-06-25 12:53:21
【问题描述】:

我设置了 Kinesis Firehose 摄取数据,AWS Lambda 执行数据转换并将传入数据放入 S3 存储桶。 S3 结构按年/月/日/小时/messages.json 组织,因此我查询的所有实际 json 文件都处于“小时”级别,所有年、月、日目录仅包含子目录。

我的问题是我需要运行查询以获取给定日期的所有数据。有没有一种简单的方法可以在“day”目录级别进行查询并返回其子目录中的所有文件,而无需对 2020/06/15/00、2020/06/15/01、2020/06/15 运行查询/02...2020/06/15/23?

我可以成功查询小时级目录,因为我可以创建一个表并定义我的 .json 文件中表示的列名和类型,但我不确定如何在 Athena 中创建一个表(如果可能)来表示一个带有子目录而不是实际文件的 day 目录。

【问题讨论】:

    标签: amazon-web-services amazon-s3 amazon-athena


    【解决方案1】:

    要仅查询一天的数据而不让 Athena 读取所有天的所有数据,您需要创建一个 partitioned table(请看第二个示例)。分区表类似于常规表,但它们包含额外的元数据,用于描述特定分区键组合的数据所在的位置。当您运行查询并为分区键指定条件时,Athena 可以确定要读取哪些位置以及要跳过哪些位置。

    如何为表配置分区键取决于数据的分区方式。在您的情况下,分区是按时间划分的,并且时间戳具有每小时粒度。您可以选择多种不同的方式来对表中的这种分区进行编码,哪种方式最好取决于您要运行的查询类型。你说你想按天查询,这是有道理的,在这种情况下会很好用。

    有两种设置方式,传统方式和新方式。新方法使用了几天前刚刚发布的功能,如果您尝试查找更多示例,您可能找不到很多示例,因此我也将向您展示传统方法。

    使用分区投影

    使用以下 SQL 创建您的表(您必须自己填写列,因为您说您已经成功创建了一个表,并且已经使用了该表中的列 - 同时修复了 S3 位置):

    CREATE EXTERNAL TABLE cszlos_firehose_data (
      -- fill in your columns here
    )
    PARTITIONED BY (
      `date` string
    )
    ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
    LOCATION 's3://cszlos-data/is/here/'
    TBLPROPERTIES (
      "projection.enabled" = "true",
      "projection.date.type" = "date",
      "projection.date.range" = "2020/06/01,NOW",
      "projection.date.format" = "yyyy/MM/dd",
      "projection.date.interval" = "1",
      "projection.date.interval.unit" = "DAYS",
      "storage.location.template" = "s3://cszlos-data/is/here/${date}"
    )
    

    这将创建一个由date 分区的表(请注意,您需要在查询中引用它,例如SELECT * FROM cszlos_firehose_data WHERE "date" = …,因为它是一个保留字,如果您想避免使用另一个名称引用它,@987654328 @ 似乎很流行,还要注意它在 DDL 中用反引号和在 DML 语句中用双引号转义)。当您查询此表并为 date 指定条件时,例如… WHERE "date" = '2020/06/05',Athena 将只读取指定日期的数据。

    该表使用Partition Projection,这是一项新功能,您可以将属性放在TBLPROPERTIES 部分中,告诉 Athena 您的分区键以及如何查找数据 - 这里我告诉 Athena 假设存在S3 上从 2020-06-01 到查询运行时间的数据(调整必要的开始日期),这意味着如果您指定该时间之前或“现在”之后的日期,Athena 将知道没有此类数据甚至在那些日子里都没有尝试阅读任何东西。 storage.location.template 属性告诉 Athena 在哪里可以找到特定日期的数据。如果您的查询指定了日期范围,例如… WHERE "date" > '2020/06/05'Athena 将生成每个日期(由projection.date.interval 属性控制)并读取s3://cszlos-data/is/here/2020-06-06s3://cszlos-data/is/here/2020-06-07 等中的数据。

    您可以找到完整的Kinesis Data Firehose example in the docs。它展示了如何使用分区的完整小时粒度,但您不希望这样,所以坚持上面的示例。

    传统方式

    传统方式与上述类似,但您必须手动添加分区以便 Athena 找到它们。首先使用以下 SQL 创建表(再次添加之前实验中的列,并修复 S3 位置):

    CREATE EXTERNAL TABLE cszlos_firehose_data (
      -- fill in your columns here
    )
    PARTITIONED BY (
      `date` string
    )
    ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
    LOCATION 's3://cszlos-data/is/here/'
    

    这与上面的 SQL 完全相同,但没有表属性。如果您现在尝试对该表运行查询,您将不会得到任何结果。原因是您需要在 Athena 知道在哪里查找数据之前告诉 Athena 分区表的分区(分区表必须有一个LOCATION,但它实际上与常规表的含义不同)。

    您可以通过多种不同方式添加分区,但最直接的交互式使用方式是使用ALTER TABLE ADD PARTITION。您可以在一个语句中添加多个分区,如下所示:

    ALTER TABLE cszlos_firehose_data ADD
    PARTITION (`date` =  '2020-06-06') LOCATION 's3://cszlos-data/is/here/2020/06/06'
    PARTITION (`date` =  '2020-06-07') LOCATION 's3://cszlos-data/is/here/2020/06/07'
    PARTITION (`date` =  '2020-06-08') LOCATION 's3://cszlos-data/is/here/2020/06/08'
    PARTITION (`date` =  '2020-06-09') LOCATION 's3://cszlos-data/is/here/2020/06/09'
    

    如果您开始阅读有关分区表的更多信息,您可能还会遇到MSCK REPAIR TABLE 语句作为加载分区的一种方式。不幸的是,这个命令真的很慢,而且它只适用于 Hive 风格的分区数据(例如…/year=2020/month=06/day=07/file.json)——所以你不能使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 2020-06-16
      • 2019-02-02
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      相关资源
      最近更新 更多