本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
亚马逊 Data Firehose 示例
当您使用 Firehose 向 Amazon S3 传输数据时,默认配置会使用与以下示例类似的密钥写入对象:
s3://bucket/prefix/yyyy/MM/dd/HH/file.extension
要创建在查询时自动查找分区的 Athena 表,而不必在新数据到达时将其添加到 Amazon Glue Data Catalog 中,而是可以使用分区投影。
以下CREATE TABLE
示例使用默认的 Firehose 配置。
CREATE EXTERNAL TABLE my_ingested_data ( ... ) ... PARTITIONED BY ( datehour STRING ) LOCATION "s3://
DOC-EXAMPLE-BUCKET
/prefix
/" TBLPROPERTIES ( "projection.enabled" = "true", "projection.datehour.type" = "date", "projection.datehour.format" = "yyyy/MM/dd/HH", "projection.datehour.range" = "2021/01/01/00,NOW", "projection.datehour.interval" = "1", "projection.datehour.interval.unit" = "HOURS", "storage.location.template" = "s3://DOC-EXAMPLE-BUCKET
/prefix
/${datehour}/" )
CREATE TABLE
语句中的 TBLPROPERTIES
子句告诉 Athena 以下内容:
-
查询表时使用分区投影
-
分区键
datehour
的类型为date
(包括可选时间) -
如何格式化日期
-
日期时间范围 请注意,必须使用逗号来分隔值,而不是使用连字符。
-
Amazon S3 上数据所在的位置。
当您查询表时,Athena 会计算 datehour
值并使用存储位置模板生成分区位置列表。
使用 date
类型
当您使用投影分区键的 date
类型时,您必须指定一个范围。由于您没有创建 Firehose 交付流之前的日期数据,因此您可以使用创建日期作为起始日期。此外,由于您没有将来日期的数据,您可以使用特殊令牌 NOW
作为结束日期。
在 CREATE TABLE
示例中,开始日期指定为 UTC 时间 2021 年 1 月 1 日午夜。
注意
配置一个与您的数据尽可能匹配的范围,以便 Athena 仅查找现有分区。
在示例表上运行查询时,Athena 将 datehour
分区键上的条件与范围结合使用来生成值。请考虑以下查询:
SELECT * FROM my_ingested_data WHERE datehour >= '2020/12/15/00' AND datehour < '2021/02/03/15'
SELECT
查询中的第一个条件使用在 CREATE TABLE
语句指定的日期范围开始之前的日期。由于分区投影配置没有为 2021 年 1 月 1 日之前的日期指定分区,因此 Athena 仅在以下位置查找数据,并忽略查询中较早的日期。
s3://bucket/prefix/2021/01/01/00/ s3://bucket/prefix/2021/01/01/01/ s3://bucket/prefix/2021/01/01/02/ ... s3://bucket/prefix/2021/02/03/12/ s3://bucket/prefix/2021/02/03/13/ s3://bucket/prefix/2021/02/03/14/
同样,如果查询在 2021 年 2 月 3 日 15:00 之前的日期和时间运行,则最后一个分区将反映当前日期和时间,而不是查询条件中的日期和时间。
如果您想查询最新数据,您可以利用 Athena 不生成未来日期的事实,并仅指定起始 datehour
,如以下示例所示。
SELECT * FROM my_ingested_data WHERE datehour >= '2021/11/09/00'
选择分区键
您可以指定分区投影如何将分区位置映射到分区键。在上一节的 CREATE TABLE
示例中,日期和小时组合成一个名为 datehour 的分区键,但也可以使用其他方案。例如,您还可以为年、月、日和小时配置具有单独分区键的表。
不过,将日期拆分为年、月、日意味着无法使用 date
分区投影类型。另一种方法是将日期与小时分开,以便仍然利用 date
分区投影类型,但要确保用来指定小时范围的查询更加易于阅读。
考虑到这一点,以下 CREATE TABLE
示例将日期与小时分开。由于 date
是 SQL 中的保留字,因此这一示例使用 day
作为表示日期的分区键的名称。
CREATE EXTERNAL TABLE my_ingested_data2 ( ... ) ... PARTITIONED BY ( day STRING, hour INT ) LOCATION "s3://
DOC-EXAMPLE-BUCKET
/prefix
/" TBLPROPERTIES ( "projection.enabled" = "true", "projection.day.type" = "date", "projection.day.format" = "yyyy/MM/dd", "projection.day.range" = "2021/01/01,NOW", "projection.day.interval" = "1", "projection.day.interval.unit" = "DAYS", "projection.hour.type" = "integer", "projection.hour.range" = "0,23", "projection.hour.digits" = "2", "storage.location.template" = "s3://DOC-EXAMPLE-BUCKET
/prefix
/${day}/${hour}/" )
在示例 CREATE TABLE
语句中,小时是一个单独的分区键,配置为整数。小时分区键的配置指定了 0 到 23 的范围,并且当 Athena 生成分区位置时,小时的格式应为两位数。
对 my_ingested_data2
表的查询可能如下所示:
SELECT * FROM my_ingested_data2 WHERE day = '2021/11/09' AND hour > 3
分区键类型和分区投影类型
请注意,第一个 CREATE TABLE
示例中的 datehour
键在分区投影配置中配置为 date
,但分区键的类型为 string
。第二个示例中的 day
也是如此。分区投影配置中的类型仅告诉 Athena 在生成分区位置时如何格式化值。您指定的类型不会更改分区键的类型 – 在查询中,datehour
和 day
属于 string
类型。
当查询包含与 day = '2021/11/09'
类似的条件时,Athena 会使用分区投影配置中指定的日期格式解析表达式右侧的字符串。在 Athena 验证日期是否在配置范围内后,它会再次使用日期格式将日期作为字符串插入到存储位置模板中。
同样,对于像 day > '2021/11/09'
这样的查询条件,Athena 会解析右侧并生成配置范围内所有匹配日期的列表。然后使用日期格式将每个日期插入到存储位置模板中以创建分区位置列表。
编写与 day > '2021-11-09'
或 day >
DATE '2021-11-09'
相同的条件将无效。在第一种情况下,日期格式不匹配(注意连字符而不是正斜杠),在第二种情况下,数据类型不匹配。
使用自定义前缀和动态分区
Firehose 可以配置自定义前缀和动态分区。使用这些功能,您可以配置 Amazon S3 键并设置更好地支持您的使用案例的分区方案。您还可以将分区投影与这些分区方案一起使用,然后进行相应的配置。
例如,您可以使用自定义前缀功能获取具有 ISO 格式日期而非默认 yyyy/MM/dd/HH
方案的 Amazon S3 键。
您还可以将自定义前缀与动态分区结合使用来提取属性,例如从 customer_id
Firehose 消息中提取属性,如以下示例所示。
prefix/!{timestamp:yyyy}-!{timestamp:MM}-!{timestamp:dd}/!{partitionKeyFromQuery:customer_id}/
使用该 Amazon S3 前缀,Firehose 传输流会向密钥写入对象,例如。s3://bucket/prefix/2021-11-01/customer-1234/file.extension
对于像 customer_id
这样的属性,其值可能事先未知,您可以使用分区投影类型 injected
并使用如下所示的 CREATE TABLE
语句:
CREATE EXTERNAL TABLE my_ingested_data3 ( ... ) ... PARTITIONED BY ( day STRING, customer_id STRING ) LOCATION "s3://
DOC-EXAMPLE-BUCKET
/prefix
/" TBLPROPERTIES ( "projection.enabled" = "true", "projection.day.type" = "date", "projection.day.format" = "yyyy-MM-dd", "projection.day.range" = "2021-01-01,NOW", "projection.day.interval" = "1", "projection.day.interval.unit" = "DAYS", "projection.customer_id.type" = "injected", "storage.location.template" = "s3://DOC-EXAMPLE-BUCKET
/prefix
/${day}/${customer_id}/" )
当您查询具有类型 injected
的分区键的表时,您的查询必须包含该分区键的值。对 my_ingested_data3
表的查询可能如下所示:
SELECT * FROM my_ingested_data3 WHERE day BETWEEN '2021-11-01' AND '2021-11-30' AND customer_id = 'customer-1234'
ISO 格式日期
由于 day
分区键的值是 ISO 格式的,您也可以使用 DATE
类型而不是 STRING
类型作为日期分区键,如以下示例所示:
PARTITIONED BY (day DATE, customer_id STRING)
查询时,此策略允许您在分区键上使用日期函数而无需解析或转换,如以下示例所示:
SELECT * FROM my_ingested_data3 WHERE day > CURRENT_DATE - INTERVAL '7' DAY AND customer_id = 'customer-1234'
注意
指定 DATE
类型的分区键时,假设您已使用自定义前缀功能创建了日期为 ISO 格式的 Amazon S3 键。如果您使用的是 Firehose 的默认 Firehose 格式yyyy/MM/dd/HH
,则必须将分区键指定为类型,string
即使对应的表属性的类型也是如此date
,如下例所示:
PARTITIONED BY ( `mydate` string) TBLPROPERTIES ( 'projection.enabled'='true', ... 'projection.mydate.type'='date', 'storage.location.template'='s3://
DOC-EXAMPLE-BUCKET
/prefix/${mydate}')