4、批量数据源接入:HDFS / Hive 作为批量数据源、分区表设计、增量与全量策略

批量数据源接入,说白了就是解决「怎么把海量历史数据稳定、高效地拉进质量检测体系」的问题。

我这些年做数据治理,接触最多的批量源就是 HDFS 和 Hive。很多团队一上来就搞实时,结果发现离线数仓的脏数据能把实时链路也带偏。嗯,批量源的质量检测,其实是整个体系的基石。

4.1 HDFS 作为批量数据源:文件级别的质量关卡

HDFS 是底层存储。数据以文件形式存在,可能是 CSV、Parquet、ORC。我个人的习惯是,在接入层就做三道检查:

  1. 文件完整性:检查 _SUCCESS 标记文件是否存在,文件大小是否与预期一致。
  2. 元数据校验:文件名是否包含日期/批次号,目录结构是否符合约定。
  3. Schema 探测:读取前 N 行,验证字段数、数据类型是否匹配。
我的经验: 曾经有个项目,上游每天凌晨 3 点往 HDFS 写数据,但写入过程是「先写临时文件,再 rename」。我们直接读临时文件,导致数据不全。后来我加了一个「文件稳定期检测」——文件最后修改时间超过 10 分钟才认为写入完成。

4.2 Hive 作为批量数据源:表级别的质量防线

Hive 表比 HDFS 文件多了一层元数据。接入时,我重点关注三个维度:

维度 检测项 说明
表结构 字段名、类型、注释 与预期 Schema 做 diff,防止字段被误删或类型变更
分区信息 分区字段、分区值列表 检查是否有异常分区(如日期格式错误)
数据量级 行数、存储大小 与历史均值对比,波动超过阈值则告警

你想想看,如果上游改了表结构,下游的 ETL 脚本直接崩掉。所以我在接入层会缓存一份「期望 Schema」,每次读取时做自动比对。

4.3 分区表设计:批量检测的命门

分区表设计得好不好,直接影响检测效率和资源消耗。我见过最糟糕的设计——按「省份+日期」双层分区,但省份字段是中文,导致 Hive 在底层生成大量目录,查询性能极差。

我的设计原则很简单:

  • 时间分区优先:按日期或小时分区,这是增量检测的基础。
  • 分区粒度适中:日分区是最常见的。小时分区适合数据量极大的场景,但管理成本也高。
  • 避免过多层级:两层分区就够了,三层以上查询计划会变复杂。
推荐的分区结构:
dt=2024-01-01/biz_type=order
其中 dt 是日期分区,biz_type 是业务类型分区。这样既能按天做增量检测,也能按业务类型做全量扫描。

4.4 增量与全量策略:什么时候用哪个?

这个问题,我每次培训都会被问到。其实选择很简单:

  • 全量策略:首次接入、数据量小(百万级以下)、需要做历史数据回溯。
  • 增量策略:日常检测、数据量大(亿级以上)、对时效性有要求。

但实际项目中,往往是混合使用。我举个例子:

某电商订单表,每天新增 500 万行。全量检测跑一次要 2 小时,太慢了。我的做法是:

  1. 每周日跑一次全量检测,做深度质量分析。
  2. 每天跑增量检测,只检测当天新增分区。
  3. 增量检测发现异常时,自动触发该分区的全量重检。
避坑指南: 我曾经在增量检测中只用了 WHERE dt = '${yesterday}',结果上游某天漏写了分区,导致当天数据全部丢失,但增量检测没报错,因为「没有数据」也被视为正常。后来我加了一条规则:如果检测到的行数为 0,必须告警。

4.5 核心流程:批量数据源接入质量检测

下面这张图,是我在多个项目中沉淀下来的接入检测流程。你可以直接拿去用。

批量数据源接入质量检测流程 HDFS / Hive 数据源 ① 文件完整性 / 元数据校验 ② Schema 比对 / 分区校验 ③ 策略选择:全量 / 增量 全量扫描:全表质量检测 增量扫描:仅检测新分区 ④ 质量结果输出 / 告警 说明:全量检测适合首次接入或周/月级深度分析;增量检测适合日常巡检,效率高、资源省

4.6 代码示例:增量检测的 Hive SQL

这是我常用的增量检测模板。核心思路是:只扫描当天分区,避免全表扫描。

-- 增量检测:检查当天分区数据质量
SET hive.exec.dynamic.partition.mode = nonstrict;

INSERT OVERWRITE TABLE dwd_quality_check_result PARTITION (dt)
SELECT
  'order' AS table_name,
  dt,
  COUNT(*) AS row_count,
  COUNT(DISTINCT order_id) AS unique_orders,
  SUM(CASE WHEN amount IS NULL THEN 1 ELSE 0 END) AS null_amount_cnt,
  SUM(CASE WHEN status NOT IN ('paid','shipped','completed') THEN 1 ELSE 0 END) AS invalid_status_cnt
FROM ods_order
WHERE dt = '${yesterday}'  -- 只扫当天分区
GROUP BY dt;

-- 结果判断:如果行数为 0 或异常率超过阈值,触发告警
SELECT
  dt,
  row_count,
  unique_orders,
  null_amount_cnt,
  invalid_status_cnt,
  CASE
    WHEN row_count = 0 THEN 'ALERT: 无数据'
    WHEN null_amount_cnt / row_count > 0.01 THEN 'ALERT: 金额空值率超过 1%'
    WHEN invalid_status_cnt / row_count > 0.05 THEN 'ALERT: 状态异常率超过 5%'
    ELSE 'PASS'
  END AS check_result
FROM dwd_quality_check_result
WHERE dt = '${yesterday}';
小技巧: 增量检测的阈值不要写死。我习惯把阈值存在配置表里,比如 quality_config 表,每天动态读取。这样业务方可以自己调整,不用改代码。

4.7 全量检测的注意事项

全量检测虽然慢,但有些场景必须用。比如:

  • 新接入的数据源,需要做一次全面的「数据体检」。
  • 发现增量检测有异常,需要回溯历史数据找根因。
  • 月底/年底的数据对账,需要全量比对。

做全量检测时,我建议:

  1. 分批次执行:按分区拆成多个任务,避免单任务 OOM。
  2. 结果增量写入:全量检测的结果表,按检测日期分区,不要覆盖历史。
  3. 设置超时机制:全量任务超过 4 小时自动 kill,防止阻塞其他任务。
我曾经踩过的坑: 有一次全量检测跑了一整天,结果发现是 Hive 表的小文件太多,导致 Map 阶段启动了几万个 Task。后来我在检测前加了一步「小文件合并」的预处理,全量检测时间从 6 小时降到了 40 分钟。

4.8 总结一下

批量数据源接入,核心就三件事:

  • 文件/表级别的元数据校验——保证数据能读、结构对。
  • 分区表设计——决定了检测效率和扩展性。
  • 增量与全量策略——按场景选,别一刀切。

我个人觉得,批量接入的质量检测,做得好的话,能拦截掉 80% 以上的数据问题。剩下的 20%,交给实时链路去处理。这样分工,体系才稳。