AWS Glue 数据存储:将单个文件添加到分区

AWS Glue Datastore: Add individual files to partitions

我有一个按天分区的 s3 目录结构 s3://userlogs/year=YYYY/month=MM/day=DD/ 我有服务器不断地用文件填充当天的目录——它们每天添加大约 6,000 个文件。添加每个文件后,我想更新 Glue 数据存储中的 table userlogs 以包含它。

问题是 AWS glue 只为我们提供了一种使用像

这样的命令将全新分区(及其相应目录)添加到 table 的方法
ALTER TABLE userlogs ADD
  PARTITION (year = '2016', month = '01', day = '01) LOCATION 's3://userlogs/year=2016/month=01/day=02/'

但是,每次我 运行 我假设 Glue 需要扫描该目录中所有可能的数千个文件的命令。

我真正想要的是某种 method/command 可以执行以下操作:

ALTER TABLE userlogs UPDATE
  PARTITION (year = '2016', month = '01', day = '01) ADD FILE's3://userlogs/year=2016/month=01/day=02/todays_file_no_3423.parquet.gz'

有没有什么方法可以实现这个目标而不涉及重构我的数据存储方式?

命令ALTER TABLE ... 不会扫描您在 S3 中的数据(因此它是免费的)。它只是定义有关您在 AWS Glue 数据目录中的数据的元信息,即应该可以使用 Athena 查询搜索的 S3 中文件的位置,因此,此命令完成所需的时间不到一秒。

因此,您不需要单独添加文件,只要您在 glue metastore 中有一个分区 "points" 到这些文件所在的 S3 位置。所以之后

ALTER TABLE userlogs ADD 
PARTITION (year = '2016', month = '01', day = '01') 
LOCATION 's3://userlogs/year=2016/month=01/day=01/';

您可以将任意数量的文件添加到 s3://userlogs/year=2016/month=01/day=01/,它们的所有内容都可以通过 Athena 进行查询。

补充说明 TL;DR

不确定 ALTER TABLE userlogs ADD PARTITION ... 的以下行为是否符合预期,但是:

  • 只检查S3 bucket是否存在,不检查S3全路径。所以下面的DDL语句会成功

    ALTER TABLE userlogs ADD 
    PARTITION (..., day='01')    LOCATION 's3://userlogs/year=2016/month=01/day=01/'
    PARTITION (..., day='wrong') LOCATION 's3://userlogs/year=2016/month=01/day=wrong_path/';
    

    正常查询也会成功,但结果不同,因为错误路径中没有文件

    SELECT COUNT(*) FROM userlogs WHERE day = '01'     -- outputs some value
    SELECT COUNT(*) FROM userlogs WHERE day = 'wrong'  -- outputs 0
    
  • 它不会检查您是否有权访问该位置。

    ALTER TABLE userlogs ADD 
    PARTITION (..., day='01')         LOCATION 's3://userlogs/year=2016/month=01/day=01/'
    PARTITION (..., day='restricted') LOCATION 's3://userlogs/year=2016/month=01/day=restricted/';
    

    这意味着元存储中指向此类位置的单个分区可能会失败 SELECT

    SELECT COUNT(*) FROM userlogs  --  error(s): Access Denied ...
    

    除非您在 WHERE 子句中排除它:

    SELECT COUNT(*) FROM userlogs WHERE day != 'restricted'
    

    或者用DROP PARTITION

    删除这个分区
    ALTER TABLE userlogs DROP PARTITION (..., day='restricted');
    -- Followed by, which will succeed
    SELECT COUNT(*) FROM userlogs
    
  • 分区值不必与位置相同(这是预期的),可以使用不同的值同时指向同一位置。

    ALTER TABLE userlogs ADD 
    PARTITION (..., day='01')    LOCATION 's3://userlogs/year=2016/month=01/day=01/'
    PARTITION (..., day='first') LOCATION 's3://userlogs/year=2016/month=01/day=01/';
    

    现在如果我们使用 WHERE 子句查询,我们将得到相同的结果。

    SELECT COUNT(*) FROM userlogs WHERE day = '01'   
    SELECT COUNT(*) FROM userlogs WHERE day = 'first'
    

    我们假设它们都输出10。但是,如果您在没有 WHERE 子句的情况下进行查询,则输出将为 20,因为 Athena 对同一位置进行了两次扫描。