在 AWS Glue 中使用分区索引 - AWS Glue

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 AWS Glue 中使用分区索引

随着时间的推移,数十万个分区被添加到一个表中。GetPartitions API 用于获取表中的分区。API 返回与请求中提供的表达式匹配的分区。

让我们以 sales_data 表为例,该表依据 CountryCategoryYearMonthcreationDate 键进行分区。如果您想获得 2020 年 2020-08-15 以后 Books 类别所有已售出商品的销售数据,则必须使用表达式 "Category = 'Books' and creationDate > '2020-08-15'" 向数据目录发出 GetPartitions 请求。

如果表中没有分区索引,则 AWS Glue 加载表的所有分区,然后使用用户在 GetPartitions 请求中提供的查询表达式筛选加载的分区。随着没有索引的表上的分区数量的增加,查询需要更多的时间来运行。借助索引,GetPartitions 查询将尝试获取分区的子集,而不是加载表中的所有分区。

关于分区索引

当您创建分区索引时,请指定给定表中已存在的分区键列表。分区索引是表中定义的分区键的子列表。可以在表中定义的分区键的任何排列上创建分区索引。对于上面的 sales_data 表,可能的索引有 (country, category, year, creationDate)、(country, category, year)、(country, category)、(country)、(category, country, year, month) 等。

数据目录将按照创建索引时提供的顺序连接分区值。随着分区被添加到表中,索引的构建是一致的。可以为字符串(string、char 和 varchar)、数值(int、bigint、long、tinyint 和 smallint)和日期 (yyyy-MM-dd) 列类型创建索引。

支持的数据类型

  • 日期 – ISO 格式的日期,例如 YYYY-MM-DD。例如,date 2020-08-15。该格式使用连字符(-)来分隔年月日。允许的日期索引范围为 0000-01-019999-12-31

  • 字符串 – 用单引号或双引号括起的字符串文本。

  • Char – 固定长度字符数据,指定长度介于 1 到 255 之间,例如 char(10)。

  • Varchar – 可变长度字符数据,具有介于 1 和 65535 之间的指定长度,例如 varchar(10)。

  • 数值 – int、bigint、long、tinyint 和 smallint

数值、字符串和日期数据类型的索引支持 =、>、>=、<、<= 以及 between(介于)运算符。索引解决方案目前仅支持 AND 逻辑运算符。在使用索引进行筛选的表达式中,将忽略带有运算符“LIKE”、“IN”、“OR”和“NOT”的子表达式。对被忽略的子表达式的筛选是在应用索引筛选后获取的分区上完成的。

对于添加到表中的每个分区,都会创建一个相应的索引项。对于具有“n”个分区的表,1 个分区索引将生成“n”个分区索引项。同一个表上的“m”个分区索引将生成“m*n”个分区索引项。每个分区索引项将根据数据目录存储的当前 AWS Glue 定价策略收费。有关存储对象定价的详细信息,请参阅 AWS Glue 定价

使用分区索引创建表

您可以在表创建过程中创建分区索引。CreateTable 请求将 PartitionIndex 对象列表作为输入。在给定的表上最多可以创建 3 个分区索引。每个分区索引都需要一个名称和一个为表定义的 partitionKeys 列表。可以使用 GetPartitionIndexes API 获取在表上创建的索引

将分区索引添加到现有表

要将分区索引添加到现有表,请使用 CreatePartitionIndex 操作。您只能为每个 CreatePartitionIndex 操作创建一个 PartitionIndex。添加索引不会影响表的可用性,因为在创建索引期间该表继续可用。

添加的分区的索引状态设置为“CREATING (正在创建)”,并开始创建索引数据。如果创建索引的过程成功,则 indexStatus 将更新为“ACTIVE (活跃)”,对于不成功的过程,索引状态将更新为“FAILED (失败)”。索引创建可能会因多种原因而失败,您可以使用 GetPartitionIndexes 操作检索失败详细信息。可能出现的故障包括:

  • ENCRYPTED_PARTITION_ERROR – 不支持在具有加密分区的表上创建索引。

  • NVALID_PARTITION_TYPE_DATA_ERROR – 当 partitionKey 值不是相应 partitionKey 数据类型的有效值时观察到。例如:具有“int”数据类型的 partitionKey 的值为“foo”。

  • MISSING_PARTITION_VALUE_ERROR – 当 indexedKeypartitionValue 不存在时观察到。当表的分区不一致时可能会发生这种情况。

  • UNSUPPORTED_PARTITION_CHARACTER_ERROR – 当索引分区键的值包含字符 \u0000、\u0001 或 \u0002 时观察到的

  • INTERNAL_ERROR – 在创建索引时发生内部错误。

描述表上的分区索引

要获取在表上创建的分区索引,请使用 GetPartitionIndexes 操作。响应返回表上的所有索引,以及每个索引的当前状态(IndexStatus)。

分区索引的 IndexStatus 将是以下之一:

  • CREATING – 索引当前正在创建中,尚不能使用。

  • ACTIVE – 索引已准备就绪,可供使用。请求可以使用索引执行优化查询。

  • DELETING – 索引当前正在被删除,无法再使用。可以使用 DeletePartitionIndex 请求删除处于活动状态的索引,这会将状态从“ACTIVE (活跃)”移至“DELETING (正在删除)”。

  • FAILED – 在现有表上创建索引失败。每个表存储最后 10 个失败的索引。

在现有表上创建的索引的可能状态转换包括:

  • CREATING (正在创建) → ACTIVE (活跃) → DELETING (正在删除)

  • CREATING (正在创建) → FAILED (失败)

使用分区索引的限制

创建分区索引后,请注意对表和分区功能的以下更改:

创建新分区(添加索引后)

在表上创建分区索引后,添加到表中的所有新分区都将针对索引键的数据类型检查进行验证。索引键的分区值将针对数据类型格式进行验证。如果数据类型检查失败,则创建分区操作将失败。对于 sales_data 表,如果为类别为类型 string 且年份为类型 int 的键 (category, year) 创建索引,则创建 YEAR 值为“foo”的新分区将失败。

启用索引后,添加具有字符 U+0000、U+00001 和 U+0002 的索引键值的分区将开始失败。

表更新

在表上创建分区索引后,您将无法修改现有分区键的分区键名称,也无法更改向该索引注册的键的类型或顺序。

使用索引进行优化的 GetPartitions 调用

当您在具有索引的表上调用 GetPartitions 时,您可以包含一个表达式,如果可能,数据目录将使用索引。索引的第一个键应传递到要用于筛选的索引的表达式中。筛选中的索引优化基于最佳效果应用。数据目录尝试尽可能多地使用索引优化,但在缺少索引或不支持的运算符的情况下,它会回退到加载所有分区的现有实现。

对于上面的 sales_data 表,让我们添加索引 [Country, Category, Year]。如果表达式中未传递“Country”,则注册的索引将无法使用索引筛选分区。您最多可以添加 3 个索引来支持各种查询模式。

让我们举一些示例表达式,看看索引是如何处理它们的:

Expressions 如何使用索引

Country = 'US'

索引将用于筛选分区。

Country = 'US' and Category = 'Shoes'

索引将用于筛选分区。

Category = 'Shoes'

不会使用索引,因为表达式中未提供“country”。将加载所有分区以返回响应。

Country = 'US' and Category = 'Shoes' and Year > '2018'

索引将用于筛选分区。

Country = 'US' and Category = 'Shoes' and Year > '2018' and month = 2

索引将用于获取 country = "US" 和 category = "shoes" 且 year > 2018 的所有分区。然后,将执行月份表达式的筛选。

Country = 'US' AND Category = 'Shoes' OR Year > '2018'

由于表达式中存在 OR 运算符,因此不会使用索引。

Country = 'US' AND Category = 'Shoes' AND (Year = 2017 OR Year = '2018')

索引将用于获取所有 country = "US" 和 category = "shoes" 的分区,然后对年份表达式进行筛选。

Country in ('US', 'UK') AND Category = 'Shoes'

索引不会用于筛选,因为当前不支持 IN 运算符。

Country = 'US' AND Category in ('Shoes', 'Books')

索引将用于获取所有 country = "US" 的分区,然后对 Category 表达式进行筛选。

Country = 'US' AND Category in ('Shoes', 'Books') AND (creationDate > '2023-9-01'

索引将用于获取所有 country = "US" 且 creationDate > '2023-9-01' 的分区,然后对 Category 表达式进行筛选。

与引擎集成

Redshift Spectrum、Amazon EMR 和 AWS Glue ETL Spark DataFrames 能够在 AWS Glue 中的索引处于 ACTIVE 状态后利用索引来获取分区。AthenaAWS Glue ETL Dynamic frames 要求您执行额外的步骤以利用索引来改进查询。

启用分区筛选

要在 Athena 中启用分区筛选,您需要按如下方式更新表属性:

  1. 在 AWS Glue 控制台中,选择 Data Catalog 下的

  2. 选择一个 表。

  3. 操作下,选择编辑表

  4. 表属性下,添加以下内容:

    • 键 – partition_filtering.enabled

    • 值 – true

  5. 选择 应用

您还可以通过在 Athena 中运行 ALTER TABLE SET PROPERTIES 查询来设置此参数。

ALTER TABLE partition_index.table_with_index SET TBLPROPERTIES ('partition_filtering.enabled' = 'true')