3. 构建第一个Glue Data Catalog

在 AWS 数据治理体系中,Glue Data Catalog 是元数据的中央仓库。它本身不存储业务数据,而是记录“数据在哪里、长什么样、如何组织”的描述信息。要让 Athena、Redshift Spectrum、EMR 或 Glue ETL 作业能够直接查询 S3 上的原始文件,第一步就是把这些文件的元数据登记进 Data Catalog。手工建表虽然可行,但当 S3 目录结构复杂、分区数量庞大时,人工维护几乎不可持续。Glue Crawler(爬虫)正是为解决这一问题而设计的自动化元数据发现工具。

一、Data Catalog 的层级结构

理解 Catalog 的结构是使用爬虫的前提。Glue Data Catalog 采用三层组织模型:数据库(Database)→ 表(Table)→ 分区(Partition),列信息则附着在表定义中。

  • 数据库:元数据的逻辑命名空间,用于隔离不同项目、环境或业务域的表。例如 sales_analytics、iot_raw。数据库本身不绑定任何存储位置。
  • 表:对应一份具有相同 Schema 的数据集合,必须指定 SerDe(序列化/反序列化器)、输入格式、存储位置(S3 前缀)和列定义。表是查询引擎识别数据的入口。
  • 分区:表内按某个或某几个列的值切分的子目录,例如 year=2024/month=06/day=15/。分区列不是数据文件中的字段,而是从路径中解析出来的“虚拟列”,用于分区裁剪(Partition Pruning),大幅减少扫描量。
  • 列统计信息:爬虫在扫描数据时会采集每列的统计特征,如数据类型、是否为空、最小值、最大值、平均长度等。这些信息写入 Catalog 后,可供查询优化器估算代价。

下面这张图展示了从 S3 存储桶到 Data Catalog 元数据对象的映射关系,以及爬虫在其中的作用位置。

S3 存储桶 s3://my-data-lake/ sales/ year=2024/ month=06/ day=15/ part-0001.parquet part-0002.parquet year=2024/month=07/ part-0001.parquet Glue Crawler 扫描 S3 路径 推断 Schema 识别分区结构 采集列统计信息 写入 Data Catalog IAM Role: AWSGlueServiceRole 读取 写入 Glue Data Catalog Database: sales_analytics Table: sales_orders Partition: year=2024/month=06 Partition: year=2024/month=07 列定义与统计信息 order_id: bigint, min=1001, max=9999 amount: double, avg=256.7 region: string, distinct=5 SerDe: ParquetHiveSerDe Location: s3://my-data-lake/sales/

二、创建爬虫的关键配置

在 Glue 控制台或通过 CLI 创建爬虫时,有几个参数直接决定元数据质量:

  • Crawler source type:选择 Data stores,指定 S3 路径。路径应指向表的根前缀,例如 s3://my-data-lake/sales/,而不是某个具体分区目录,否则爬虫只会发现单个分区。
  • IAM Role:爬虫需要读取 S3 的权限,以及写入 Glue Catalog 的权限。通常使用 AWSGlueServiceRole 托管策略,并附加 S3 读取策略。
  • Target database:指定元数据写入哪个 Glue 数据库。如果数据库不存在,爬虫可以自动创建。
  • Table prefix:可选,用于给爬虫生成的表名加前缀,便于区分来源。
  • Schema change policy:控制当数据 Schema 变化时爬虫的行为。推荐设置为 Update the table definition in the Data Catalog,并勾选 Ignore the change and don't update the table 作为降级策略,避免误删列。
  • Partition detection:爬虫默认会识别 Hive 风格的分区路径(key=value/)。如果数据使用非标准分区命名,需要自定义分类器或调整路径结构。

三、实操:从零构建第一个 Catalog

假设我们有一个 S3 存储桶 my-data-lake,其中 sales/ 前缀下存放了按年月分区的 Parquet 文件。目标是在 Glue 中创建数据库 sales_analytics,并让爬虫自动生成表 sales_orders。

首先通过 AWS CLI 创建数据库:

aws glue create-database \
  --database-input '{"Name":"sales_analytics","Description":"销售分析元数据库"}'

然后创建爬虫。以下命令指定了 S3 路径、IAM 角色、目标数据库,并设置每天凌晨 2 点自动运行:

aws glue create-crawler \
  --name sales-crawler \
  --role AWSGlueServiceRole-SalesCrawler \
  --database-name sales_analytics \
  --targets '{"S3Targets":[{"Path":"s3://my-data-lake/sales/"}]}' \
  --schedule "cron(0 2 * * ? *)" \
  --schema-change-policy '{"UpdateBehavior":"UPDATE_IN_DATABASE","DeleteBehavior":"LOG"}'

启动爬虫并观察运行状态:

aws glue start-crawler --name sales-crawler
aws glue get-crawler --name sales-crawler --query 'Crawler.State'

当状态从 RUNNING 变为 READY 后,查看生成的表:

aws glue get-table --database-name sales_analytics --name sales_orders

返回的 JSON 中会包含 StorageDescriptor(列定义、SerDe、Location)、PartitionKeys(分区列 year、month)以及 Parameters(如 classification=parquet、sizeKey 等)。如果爬虫正确识别了分区,还会在 Partitions 中列出每个分区对应的 S3 路径。

四、如何判断爬虫结果是否正确

爬虫运行结束后,不要只看“成功”状态,而应核对以下要点:

  • 表数量:爬虫可能把不同 Schema 的文件识别为多张表。如果预期一张表却生成了多张,说明 S3 路径下混入了结构不一致的文件,需要调整路径或使用排除模式。
  • 分区列:检查 PartitionKeys 是否包含预期的分区字段。如果分区列出现在普通列中,说明路径不符合 Hive 风格,或爬虫未启用分区识别。
  • 列类型:Parquet 文件的 Schema 通常能被准确推断;CSV 文件则可能把数字识别为 string。必要时可在爬虫的 Classifier 中指定 CSV 的列类型,或事后用 UpdateTable 修正。
  • 列统计信息:在 Glue 控制台的表详情页可以看到每列的统计信息。如果统计信息为空,可能是爬虫配置中未启用 ComputeStatistics,或数据文件格式不支持统计采集。
爬虫每次运行都会重新扫描 S3 路径。对于分区数量很大的表,全量扫描可能耗时较长。可以在爬虫配置中设置 RecrawlPolicy 为 CRAWL_NEW_FOLDERS_ONLY,只发现新增分区,减少重复扫描开销。

五、常见问题与排查

初次使用爬虫时,最常遇到的问题是“表生成了,但查询报错”。这通常不是 Catalog 本身的问题,而是元数据与数据文件不匹配。例如,爬虫把 CSV 文件的列名识别为 col0、col1,而实际查询时按业务列名引用,就会失败。此时需要在爬虫中配置 CSV Classifier,指定 withHeader 为 true,或手动修改表定义。

另一个常见问题是分区路径包含特殊字符(如空格、中文),导致 Athena 无法解析。建议 S3 分区路径统一使用小写字母、数字和下划线,并遵循 key=value 格式。

最后,爬虫生成的表默认使用 ParquetHiveSerDe 或 LazySimpleSerDe。如果数据是 JSON 或 ORC,需要确认爬虫是否选择了正确的分类器。可以在爬虫的 Classifiers 列表中显式指定,避免自动推断出错。