跳至内容

如何防止在 AWS Glue 爬网程序运行期间创建多个表?

3 分钟阅读
0

AWS Glue 爬网程序正在从我的源数据创建多个表。我想知道我该如何做才能防止这种情况继续发生。

简短描述

在第一次 AWS Glue 爬网程序运行期间,爬网程序会读取前 1000 条记录或每个文件的前一兆字节来推断架构。爬网程序读取的数据量取决于文件格式和有效记录的可用性。

例如,如果输入的是 JSON 文件,则爬网程序会读取该文件的前 1 MB。如果爬网程序在文件的前 1 MB 内读取到有效记录,则爬网程序会推断出架构。如果爬网程序无法推断出架构,则它会以 1 MB 的增量读取该文件,最多读取 10 MB。

对于.csv 文件,爬网程序会读取前 1000 条记录或前 1 MB 的数据,以先到者为准。对于 Parquet 文件,爬网程序直接从文件中推断架构。

爬网程序会将从所有子文件夹和文件中推断出的架构进行比较,然后创建表。

当您的源数据文件中的以下参数不使用这些相同配置时,爬网程序会创建多个表:

  • 格式,例如 .csv、Parquet 或 JSON
  • 压缩类型,例如 SNAPPY、gzip 或 bzip2
  • 架构
  • Amazon Simple Storage Service (Amazon S3) 分区的结构

解决方法

检查爬网程序日志

要确定导致爬网程序创建多个表的文件,请完成以下步骤:

  1. 打开 AWS Glue 控制台
  2. 在导航窗格中,选择 Crawlers(爬网程序)。
  3. 选择要检查的爬网程序。
  4. 选择 Logs(日志)链接,以在 Amazon CloudWatch 控制台上查看日志。

如果 AWS Glue 在上一次爬网程序运行期间创建了多个表,则日志将包括与以下内容类似的条目:

[439d6bb5-ce7b-4fb7-9b4d-805346a37f88] INFO : Created table
2_part_00000_24cab769_750d_4ef0_9663_0cc6228ac858_c000_snappy_parquet in
database glue

[439d6bb5-ce7b-4fb7-9b4d-805346a37f88] INFO : Created table
2_part_00000_3518b196_caf5_481f_ba4f_3e968cbbdd67_c000_snappy_parquet in
database glue

[439d6bb5-ce7b-4fb7-9b4d-805346a37f88] INFO : Created table
2_part_00000_6d2fffc2_a893_4531_89fa_72c6224bb2d6_c000_snappy_parquet in
database glue

日志条目包括导致爬网程序创建多个表的文件的名称。

防止创建多个表

为防止创建多个表,请针对您的用例执行以下操作之一。

确认数据文件使用相同的架构、格式和压缩类型

在某些情况下,文件使用不同的架构。例如,使用架构 A 时字段 X 为 INT 类型,使用架构 B 时字段 X 为 BOOL 类型。

对于此用例,请使用 from_options 函数运行 AWS Glue 提取、转换、加载 (ETL) 作业来读取异常值数据。然后,在您的源中将异常值数据类型转换为正确或最常见的数据类型。

您也可以使用现有表 DDL 在 Amazon Athena 中手动创建表。然后,运行 AWS Glue 爬网程序来更新表元数据。配置爬网程序,使其不会覆盖表的现有架构

创建爬网程序时合并兼容的架构

爬网程序在文件夹级别推断架构,并会比较所有文件夹的架构。爬网程序会检查这些架构是否匹配以及分区阈值是否高于 70%。如果匹配,则会将这些架构表示为表的分区。如果不匹配,则爬网程序会为每个文件夹创建一个表。这会导致表的数量增加。

您的数据在某些输入文件中可能有不同的架构,而在其他文件中可能有类似的架构。创建爬网程序时,请合并兼容的架构。

AWS Glue 控制台Configure the crawler's output(配置爬网程序输出)页面上,在 Grouping behavior for S3 data (optional)(S3 数据的分组行为(可选))下,选择 Create a single schema for each S3 path(为每条 S3 路径创建单个架构)。如果数据兼容,则爬网程序在评估路径中的 Amazon S3 对象时会忽略架构相似性。

有关详细信息,请参阅为每条 Amazon S3 包含路径创建单个架构

检查您的输入文件是否有不同的 Amazon S3 路径

当 Amazon S3 前缀内的结构不一致时,爬网程序会将每个路径假定为一个单独的表。然后,爬网程序会创建多个表。如果您的输入文件具有不同的 Amazon S3 结构或路径,则默认情况下,爬网程序会创建多个表。

例如,如果您在 s3://doc-example-bucket/doc-example-key/doc-example-table Amazon S3 路径上运行爬网程序,该路径的分区结构类似于以下:

  • s3://doc-example-bucket/doc-example-key/doc-example-table/dt=2020-08-20/doc-example-file1.csv
  • s3://doc-example-bucket/doc-example-key/doc-example-table/dt=2020-08-21/dox-example-file2.csv
  • s3://doc-example-bucket/doc-example-key/doc-example-table/dt=2020-08-22/doc-example-file3.csv

那么请将以下文件添加到前三个文件中:

  • s3://doc-example-bucket/doc-example-key/doc-example-table/dox-example-file4.csv
  • s3:// doc-example-bucket/doc-example-key/doc-example-table/doc-example-file5.csv

由于文件夹分区结构不一致,爬网程序会在另一次爬网程序运行中创建五个单独的表。

为避免出现此问题,请手动或以编程方式确认架构是否一致。在前面的示例中,您可以删除不含 dt=xxxx-xx-xx 分区的 Amazon S3 文件,也可以为文件 doc-example-file4.csvdoc-example-file5.csv 添加分区。要排除不需要的文件或文件夹,请使用排除模式

使用一致的标头

使用 .csv 格式的数据时,请始终使用标头。如果您的某些文件具有标头而其他文件没有,则爬网程序会创建多个表。

删除爬网程序运行创建的多个表

从 CloudWatch 日志的爬网程序运行中筛选表。然后,调用 BatchDeleteTable API 来删除这些表。

完成以下步骤:

  1. 打开 AWS Glue 控制台
  2. 在导航窗格中,选择 Crawlers(爬网程序)。
  3. Crawler runs(爬网程序运行)下,选择目标爬网程序名称。
  4. 选择 View run details(查看运行详细信息)。
  5. Crawler run details(爬网程序运行详细信息)页面上,记下要在 BatchDeleteTable 调用中使用的爬网程序运行的 ID。
  6. 选择 CloudWatch logs(CloudWatch 日志),然后选择 /aws-glue/crawlers 日志组。
  7. 选择 Actions(操作),然后选择 Export data to Amazon S3(将数据导出到 Amazon S3)。
  8. 输入以下信息以导出数据:
    对于 time range(时间范围),请使用爬网程序运行的开始和结束时间。
    对于 stream prefix(流前缀),请添加爬网程序名称。
    选择您的目标 S3 存储桶和前缀以导出爬网程序运行日志。
  9. /aws-glue/crawlers 日志组中,选择 Actions(操作),然后选择 View all exports to Amazon S3(查看导出到 Amazon S3 的所有数据)。
  10. /aws-glue/crawlers 日志组和目标 S3 存储桶选择导出任务。
  11. 选择 View in Amazon S3(在 Amazon S3 中查看)。
  12. Amazon S3 控制台上,选择具有目标爬网程序名称的文件夹。
  13. 将导出的.gz 格式的日志文件下载到本地计算机或 Amazon Elastic Compute Cloud (Amazon EC2) 实例。然后,将文件解压缩到本地路径。记下路径位置,以在 BatchDeleteTable 调用中使用。
  14. 要筛选表,请从本地计算机或 EC2 实例扫描解压缩的文件。
  15. 调用 AWS Glue BatchDeleteTable API 来删除这些表。
    示例脚本:
import boto3
import re

# input parameters
catalogId='CatalogId'
database = 'databaseName'
crawlId= 'crawlRunId'
logFilePath = 'local_decompressed_file_path'

# function to extract the created tables by the given crawl run id in target database
def extract_table_info(file_path, target_crawl_id, target_database):
    list_tables = []

    with open(file_path, 'r') as file:
        for line in file:
            match = re.search(f'.*\\[{target_crawl_id}\\] INFO : Created table (\\w+(?:_[a-f0-9]+)*) in database {target_database}', line)
            if match:
                table_name = match.group(1)

                list_tables.append(table_name)
    return list(set(list_tables))

createdTables = extract_table_info(logFilePath, crawlId, database)

# initialize the Glue client and make batch_delete_table API calls to delete the created tables
client = boto3.client('glue')

for i in range(len(createdTables) // 100 + 1):
    tables_to_delete = createdTables[100 * i : 100 * (i + 1)]
    response = client.batch_delete_table(
        CatalogId=catalogId,
        DatabaseName=database,
        TablesToDelete=tables_to_delete
    )
    print(i)
    print(response)

**注意:**请将示例输入参数替换为您的输入参数。前面的示例脚本使用本地计算机或 EC2 实例上的默认 AWS 区域设置。要在 boto3 中更改区域,请参阅配置

相关信息

在 AWS Glue 中管理用于 ETL 输出的分区

自定义爬网程序行为

使用控制台将日志数据导出到 Amazon S3

AWS 官方已更新 1 年前