【问题标题】:Athena Partition Projections and mixed file schemasAthena 分区投影和混合文件模式
【发布时间】:2023-04-10 03:38:01
【问题描述】:

我想知道 Athena 分区投影如何处理包含具有不同字段的 CSV 文件的文件夹。假设我的存储桶按年、月和日划分为 s3://SalesPurchases/{year}/{month}/{day}。在每 15 分钟的时间间隔内,我生成两个文件,描述在该时间间隔内进行的销售和购买。例如,文件名将是 Sales-15min-03:00.csv,表示它是在凌晨 3 点生成的,并保存了前 15 分钟的更新。这些文件包含以下字段:

Sales: id, description, amount - (all strings)
Purchases: id, description, vendor, amount - (all strings)

如果我为销售创建一个表:

CREATE EXTERNAL TABLE sales_data (
id string,
description string,
amount string
)
PARTITIONED BY (
  `year` string,
  `month` string,
  `day` string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
LOCATION 's3://SalesPurchases/'
TBLPROPERTIES (
  "skip.header.line.count" = "1",
  "projection.enabled" = "true",
  "projection.year.type" = "integer",
  "projection.year.range" = "2020,2021",
  "projection.month.type" = "integer",
  "projection.month.range" = "01,12",
  "projection.day.type" = "integer",
  "projection.day.range" = "01,31",
  "storage.location.template" = "s3://SalesPurchases/${year}/${month}/${day}"
)

我只是想知道这种方法的效率。此 CREATE 语句中没有指示仅过滤“销售”文件。当实际查询 year=2020,month=01,day=01 的数据时,我相信该分区中的所有 Sales 和 Purchases 文件都会被读取。我开始相信这与通过胶水爬虫创建数据目录条目的方式没有什么不同。它们都将定义相同的模式信息。但是我确实相信分区投影在某种程度上更优化。

由于 Sales 中的所有字段都是 Purchases 中字段的子集,因此我也有兴趣了解如何处理。

我注意到的另一个奇怪之处是,当我使用上面的 create table 语句时,当需要查询时,我会执行类似的操作

select * from sales_data limit 10

select count(*) from sales_data

我得到零结果。我必须在查询中专门包含更多过滤器以获取有意义的信息,例如

select * from sales_data where year = '2020' and month = '01' and day = '01' limit 10

分区投影是不是很奇怪?然而,当使用爬虫生成架构信息时,情况并非如此。在这种情况下,select * from sales_data limit 10 将返回非零结果。这是为什么呢?

谢谢。

【问题讨论】:

    标签: amazon-athena


    【解决方案1】:

    Athena 要求表中的所有文件都具有相同的架构。当它运行查询时,它将列出并处理表LOCATION(或表的分区'LOCATION)给定的S3前缀中的所有文件。没有办法告诉它按名称过滤文件,它总是会处理所有文件。无论您是否使用分区投影,这都是一样的。

    Glue Crawler 也不是解决此问题的方法,如果您在此设置中使用它会完全搞砸。

    将您的销售和采购文件放在单独的前缀中并创建单独的表。


    您的查询最终结果为零的原因是您需要将月份和日期分区键配置为零填充:

    "projection.month.digits" = "2"
    "projection.day.digits" = "2"
    

    令人困惑的是,该范围允许以零为前缀的值,即使它实际上并未将范围配置为以零为前缀。

    【讨论】:

    • 感谢您的回复,包括零填充现在可以使用。我仍然不明白为什么零填充解决了这个问题。当我有select * from sales_data limit 10 时,它不应该尝试扫描模板给出的所有数据吗?好的,所以它可能会因为一些零填充问题而错过 day=(1 到 9),但肯定会在其余部分(10 到 31)上恢复,因为它们没有以零为前缀。跨度>
    • 另一件事,关于您对 Glue Crawlers 的评论。如果我设置了一个销售爬虫来排除产品文件(通过排除模式),那么生成的架构不会类似于我在原始帖子中定义的 CREATE EXTERNAL TABLE 架构(显然没有分区投影的东西)。那么胶水爬虫派生模式解决方案真的和创建外部表模式一样糟糕吗?因此,无论哪种情况,我都应该设置两个前缀:s3://products/{year}/{month}/{day} 和 s3://sales/{year}/{month}/{day}让事情更有效地运行?谢谢
    • 你应该设置两个前缀,是的。排除模式可以用来排除分区,但它们的设计方式看起来可以用来排除文件。就像 Glue 中的几乎所有其他东西一样,这个 API 很糟糕。看起来它可以做一般的事情,但除非你以非常狭窄的方式使用它,否则它会很糟糕。在您的情况下,架构可能看起来不错,但运行查询仍会获取这两种文件,并且会出错或产生混乱的结果。
    • 我猜为什么 PP 即使在您执行 select * from sales_data 时也找不到任何东西,因为您没有第 10、11、12 个月的数据。
    • 感谢您的回复和帮助。确定 Glue API 的注意事项确实需要一些时间。我现在一直在远离爬虫,除非所有文件都具有相同的架构;并倾向于分区投影,并相应地对数据进行分区。关于select * from sales_data 的问题,我确实有 10、11 和 12 的数据。不知道出了什么问题,但我现在指定数字 = 2 并且它正在工作。我想我会留下它:) 再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2019-03-21
    • 2013-11-26
    • 1970-01-01
    • 2021-02-25
    • 2021-03-16
    • 2021-06-05
    • 1970-01-01
    • 2021-04-30
    相关资源
    最近更新 更多