4. AWS Glue数据目录与爬网程序
在数据仓库与分析平台中,真正让查询引擎“知道数据在哪里、长什么样”的,不是文件本身,而是元数据。AWS Glue Data Catalog(数据目录)就是 AWS 上集中存放这类元数据的服务:它把数据库、表、列、分区、数据类型、存储位置、SerDe 等信息统一登记,供 Athena、Redshift Spectrum、EMR、Glue ETL 等引擎共享。而 Glue Crawler(爬网程序)则是自动发现数据、推断结构并把结果写入数据目录的“元数据采集器”。理解这两者的分工与配合,是构建可维护数据湖目录的第一步。
数据目录的层级结构
Glue 数据目录采用三层结构:Catalog(目录)→ Database(数据库)→ Table(表)。这里的 Database 并不是 RDS 那种物理数据库,而是一个逻辑命名空间,用来给表分组,例如按业务域划分为 sales_db、logistics_db。Table 描述一份数据集的元数据,包含列名、列类型、分区键、表参数、SerDe 与 InputFormat/OutputFormat,以及最关键的 Location——数据实际所在的 S3 路径。分区(Partition)是表的子级,每个分区记录一组分区键值及其对应的 S3 前缀。
需要特别区分两个概念:表定义与数据本身。数据目录只存元数据,不存数据。因此当 S3 中新增文件时,目录不会自动更新,必须由爬网程序、Glue ETL 作业或手动 API 调用去刷新。这也是很多“Athena 查不到新数据”问题的根因。
爬网程序的工作机制
爬网程序的核心任务是:扫描数据源 → 分类文件格式 → 推断 Schema → 在目录中创建或更新表。它的执行过程可以拆成几个关键环节。
首先是数据源与路径。爬网程序支持 S3、JDBC(RDS、Redshift)、DynamoDB 等。以 S3 为例,需要指定一个或多个 S3 路径,路径的层级设计直接决定分区识别效果。例如:
s3://analytics-lake/orders/year=2024/month=06/day=15/part-0001.parquet
这种 key=value 的 Hive 风格目录,爬网程序可以自动识别为分区键 year、month、day。如果目录是 2024/06/15/ 这种无键名结构,则无法自动推断分区语义,只能作为普通路径。
其次是分类器(Classifier)。爬网程序内置了 CSV、JSON、Parquet、ORC、Avro、XML 等分类器,按文件扩展名、文件头魔数、内容采样综合判断格式。当内置分类器无法满足需求(例如自定义日志格式、特殊分隔符),可以编写 Grok 或 CSV 自定义分类器,并指定优先级。分类器决定了用哪种 SerDe 去解析数据,是 Schema 推断准确性的前提。
第三是Schema 推断。爬网程序会抽样读取文件(默认最多若干 MB),推断每列的名称与数据类型。这里有几个容易踩坑的点:CSV 中数字列若混有空值或异常字符,可能被推断为 string;JSON 中嵌套结构会被展开为 struct;Parquet/ORC 自带 Schema,推断最可靠。推断结果并非绝对正确,因此爬网程序提供了爬网程序配置选项来干预行为。
关键配置项与行为控制
创建爬网程序时,以下配置对结果影响最大:
- Schema 变更策略:
Update the table definition in the Data Catalog(默认,合并新列)、Add new columns only(只加列不删列)、Ignore the change and don't update the table(忽略变化)。生产环境常用“只加列”,避免误删导致下游查询失败。 - 删除行为:
Delete tables and partitions from the Data Catalog会在源数据消失时同步删除目录条目;若关闭,则保留旧表,适合需要稳定目录的场景。 - 表前缀:当多个爬网程序写入同一数据库时,用前缀区分来源,例如
raw_、curated_。 - 分区更新:可设置是否仅爬取新分区、是否忽略已存在分区,减少重复扫描成本。
- 并发与超时:通过 DPU 数量控制吞吐,路径过多时可拆分多个爬网程序并行执行。
数据目录集成实战
下面以一个订单数据湖为例,走一遍完整流程。假设 S3 中已有按天分区的 Parquet 数据,路径为 s3://analytics-lake/orders/year=2024/month=06/。
第一步,创建数据库。在 Glue 控制台或 CLI 中建立逻辑库:
aws glue create-database --database-input '{"Name":"sales_db","Description":"销售域数据目录"}'
第二步,创建爬网程序。指定数据源为上述 S3 路径,目标数据库为 sales_db,Schema 变更策略选“只加列”,并启用分区更新。若数据格式为 Parquet,分类器会自动识别,无需自定义。
第三步,运行并观察结果。爬网程序执行后,在数据目录中会生成表 orders,列包括 order_id、customer_id、amount、order_time 等,分区键为 year、month。此时用 Athena 查询:
SELECT year, month, count(*) AS cnt, sum(amount) AS total
FROM sales_db.orders
WHERE year='2024' AND month='06'
GROUP BY year, month;
如果查询返回 0 行,通常不是数据问题,而是分区未登记或 Location 指向错误。此时应检查 SHOW PARTITIONS sales_db.orders; 的输出,确认分区键与 S3 目录是否一致。
第四步,验证与迭代。当上游新增 month=07 数据后,重新运行爬网程序,目录中会新增对应分区。若某列类型被误判为 string,可在目录中手动修改列类型,或调整分类器后重爬。对于频繁变更的表,建议把爬网程序纳入调度(如 EventBridge 定时触发),实现元数据自动同步。
常见问题与判断依据
实践中,爬网程序最常见的问题有三类。第一类是分区未识别:表现为 Athena 查询全表有数据、按分区过滤却为空。判断方法是执行 SHOW PARTITIONS,若返回空,说明目录中没有分区条目,需检查 S3 路径是否符合 key=value 格式,或爬网程序是否开启了分区更新。第二类是列类型错误:CSV 中数字被识别为 string,导致 sum() 报错。此时可在目录中手动修正列类型,或改用 Parquet 等自带 Schema 的格式。第三类是表重复创建:多个爬网程序指向同一路径但表前缀不同,会生成多张表。应统一路径归属,用前缀区分来源而非重复爬取。
最后要建立的一个认知是:数据目录是“共享的元数据契约”,爬网程序只是维护这份契约的一种自动化手段。对于结构稳定的核心表,可以手动定义表结构并关闭爬网,避免自动推断带来的不确定性;对于频繁新增、格式多变的原始数据,则用爬网程序自动同步。两者结合,才能让数据湖的元数据既准确又可持续维护。