如何访问分区的雅典娜表的子目录中的数据

时间:2019-07-01 13:19:36

标签: aws-glue aws-glue-data-catalog

我有一个每天都有分区的Athena表,其中实际文件按小时在“子目录”中,如下所示:

s3://my-bucket/data/2019/06/27/00/00001.json
s3://my-bucket/data/2019/06/27/00/00002.json
s3://my-bucket/data/2019/06/27/01/00001.json
s3://my-bucket/data/2019/06/27/01/00002.json

Athena可以毫无问题地查询该表并找到我的数据,但是在使用AWS Glue时,它似乎无法找到该数据。

ALTER TABLE mytable ADD 
PARTITION (year=2019, month=06, day=27) LOCATION 's3://my-bucket/data/2019/06/27/01';

select day, count(*)
from mytable
group by day;

day .   count
27 .    145431

我已经尝试过将分区的位置更改为以斜杠(s3://my-bucket/data/2019/06/27/01/)结尾,但这无济于事。

以下是Glue中的分区属性。我希望storedAsSubDirectories设置可以告诉它迭代子目录,但事实并非如此:

{
    "StorageDescriptor": {
        "cols": {
            "FieldSchema": [
                {
                    "name": "userid",
                    "type": "string",
                    "comment": ""
                },
                {
                    "name": "labels",
                    "type": "array<string>",
                    "comment": ""
                }
            ]
        },
        "location": "s3://my-bucket/data/2019/06/27/01/",
        "inputFormat": "org.apache.hadoop.mapred.TextInputFormat",
        "outputFormat": "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat",
        "compressed": "false",
        "numBuckets": "0",
        "SerDeInfo": {
            "name": "JsonSerDe",
            "serializationLib": "org.openx.data.jsonserde.JsonSerDe",
            "parameters": {
                "serialization.format": "1"
            }
        },
        "bucketCols": [],
        "sortCols": [],
        "parameters": {},
        "SkewedInfo": {
            "skewedColNames": [],
            "skewedColValues": [],
            "skewedColValueLocationMaps": {}
        },
        "storedAsSubDirectories": "true"
    },
    "parameters": {}
}

当Glue在相同的分区/表上运行时,它将发现0行。

但是,如果所有数据文件都出现在分区的根“目录”中(即s3://my-bucket/data/2019/06/27/00001.json),则Athena和Glue都可以找到数据。

是否有某些原因导致Glue无法找到数据文件?我不希望每个小时都创建一个分区,因为那将意味着每年8700个分区(而Athena的每个表限制为20,000个分区)。

3 个答案:

答案 0 :(得分:0)

AWS Glue数据目录应该用于定义有关实际数据的元信息,例如表模式,分区的位置等。分区的概念是限制Athena仅扫描S3存储桶中某些目标的方法,以提高速度和成本效益。当使用Athena查询S3存储桶中的数据时,它会使用Glue数据目录中指定的表定义。这也意味着,当您在Athena中执行DDL语句时,将在Glue datacatalog中创建相应的表。所以我不确定“胶水发现0行”

是什么意思

如果您使用Athena这样创建表格:

CREATE EXTERNAL TABLE `mytable`(
  `labels` array<string>, 
  `userid` string)
PARTITIONED BY ( 
  `year` string, 
  `month` string, 
  `day` string, 
  `hour` string)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
WITH SERDEPROPERTIES ( 
  'paths'='labels,userid,') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://my-bucket/data/'

请注意,LOCATION指向分区开始的位置。然后添加一个分区应该像这样:

ALTER TABLE mytable 
ADD PARTITION (year=2019, month=06, day=27, hour=00) 
LOCATION 's3://my-bucket/data/2019/06/27/00/';
ALTER TABLE mytable 
ADD PARTITION (year=2019, month=06, day=28, hour=00) 
LOCATION 's3://my-bucket/data/2019/06/28/00/';

在这两个DDL查询语句之后,您应该可以在mytable标签下的两个分区的Glue数据目录中看到View partitions。现在,如果您运行的查询中没有WHERE语句:

SELECT 
    "day", COUNT(*)
FROM 
    mytable
GROUP BY "day";

然后将扫描分区指定的所有数据,您应该得到

| day | count          |
|-----|----------------|
| 27  | some number    |
| 28  | another number |

现在,如果您要计算特定日期内的记录,则需要添加WHERE语句

SELECT 
    "day", COUNT(*)
FROM 
    mytable
WHERE(
    "day" = '27'
)
GROUP BY "day";

然后将仅扫描s3://my-bucket/data/2019/06/27/下的数据,您应该得到类似以下内容:

| day | count          |
|-----|----------------|
| 27  | some number    |

附加说明

  • 根据AWS,Glue目录中的表最多可以包含10 million partitions,因此每年8700个分区几乎不会成为问题。
  • AWS不向您收取雅典娜执行的DDL语句的费用。
  • 如果您在S3中的路径遵循HIVE约定,即s3://my-bucket/data/year=2019/month=06/day=27/hour=00/,则在定义表后,您只需运行MSCK REPAIR TABLE mytable所有分区将被添加到Glue中的表中数据目录。
  • 对于大量分区,运行ALTER TABLE mytable ADD PARTITION ...是不可行的。相反,您可以使用:

    1. 胶履带。根据我的经验,这仅在您对数据不甚了解且数据量很大时才有用。这是AWS pricing
    2. 适用于python的AWS开发工具包,例如boto3。它为Athena和Glue客户提供API。

    对于Athena client,您可以将ALTER TABLE mytable ADD PARTITION ...语句生成为字符串,然后将其发送执行。这是一个post on Medium,可以帮助您入门。

    您还可以使用Glue client通过batch_create_partitioncreate_partition方法执行相同的操作,但这将需要与Athena客户程序不同的输入

更新2019-07-03

如果您的数据具有类似结构

s3://my-bucket/data/2019/06/27/00/00001.json
s3://my-bucket/data/2019/06/27/00/00002.json
s3://my-bucket/data/2019/06/27/01/00001.json
s3://my-bucket/data/2019/06/27/01/00002.json
...
s3://my-bucket/data/2019/06/28/00/00001.json
s3://my-bucket/data/2019/06/28/00/00002.json
s3://my-bucket/data/2019/06/28/01/00001.json
s3://my-bucket/data/2019/06/28/01/00002.json

但是您只希望只有3个分区,即年,月,日,那么表的定义应考虑到这一点:

CREATE EXTERNAL TABLE `mytable`(
  `labels` array<string>, 
  `userid` string)
PARTITIONED BY (  -- Here we specify only three columns 
  `year` string, 
  `month` string, 
  `day` string)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
WITH SERDEPROPERTIES ( 
  'paths'='labels,userid,') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://my-bucket/data/'

然后用于添加分区的DDL语句应为:

ALTER TABLE mytable
ADD PARTITION (year=2019, month=06, day=27)
LOCATION 's3://my-bucket/data/2019/06/27/';  -- Stop at day level

ALTER TABLE mytable
ADD PARTITION (year=2019, month=06, day=28)
LOCATION 's3://my-bucket/data/2019/06/28/';  -- Stop at day level

请记住,在S3中没有文件夹或目录之类的东西。这就是我在Athena,Glue和S3上下文中看到分区和位置的方式。分区是一组S3对象的抽象,其中分组是通过针对某个“前缀” <=>位置过滤所有对象来定义的。因此,当您指定LOCATION时,请停在“日级别”。虽然,您可以在“小时级别”停下来,例如s3://my-bucket/data/2019/06/28/01/,但是如果您希望Athena能够扫描它们,则需要在所有其他小时中创建分区。最重要的是,分区值的组合应该是唯一的(等同于定义4个分区),否则AWS不允许创建它。

只需在我的AWS账户中使用类似于您的S3路径的数据进行测试,并且能够查看Glue数据目录中指向正确目的地的分区。

答案 1 :(得分:0)

显然,create_dynamic_frame上有一个未记录的“递归”附加选项: egrep -o ' [0-9,]*|^[0-9,]*' | tr , . | tr -d ' '

示例:

additional_options = {"recurse": True}

我刚刚使用此选项测试了我的Glue作业,可以确认现在可以找到所有s3文件。

答案 2 :(得分:0)

我也遇到过同样的情况。

我为S3桶手动创建了Glue数据目录表。该目录包含一些未分配为任何分区键的子目录。通过目录表,Athena查询甚至可以处理子目录中的所有文件。但是胶水作业create_dynamic_frame.from_catalog却没有。将additional_options = {"recurse": True}添加到from_catalog,Glue Job在子目录中查找文件。

在我的情况下,目录表具有分区属性"storedAsSubDirectories" = "false",因为当我使用Glue控制台或Athena DDL查询创建目录表时,该属性是自动分配的,并且无法触摸控制台上的值。尽管具有此属性,但它可以与附加选项recurse=True一起使用。我怀疑属性storedAsSubDirectories不适用于该词的含义。

正如@ 3nochroot所说,即使在今天,似乎也没有在官方文件中声明。