专家(二):Claude Code 数据工程实战:dbt + Airflow + Spark 全流程,$0.22 搭完电商分析管道

专家(二):Claude Code × 数据工程------Airflow + dbt + Spark 全流程

Windows 10/11 · Claude Code v2.1.32+ · DeepSeek V4 Pro / Anthropic API · 🟡 中度时效 · 最后更新 2026-05-18

一、这篇教程解决什么问题

一句话定位:读完本篇,你会用 Claude Code 从零搭建一条电商数据分析管道------从原始日志到 BI 看板,覆盖 dbt 数据建模(Star Schema)、Airflow DAG 编排(TaskFlow API + 动态任务 + SLA 监控)、PySpark 批处理(Join 优化 + 数据倾斜修复)、Great Expectations 数据质量自动化检查,全程 AI 主导、你来审校。

这是专家系列第二篇。上一篇我们用 Claude Code 拆了 6 个微服务,这篇换一个赛道------数据工程。数据工程是 AI 辅助开发覆盖最少、但需求增长最快的领域:大量 YAML/SQL/Python 胶水代码、配置文件驱动的工具链、重复性高的管道搭建------这些恰恰是 Claude Code 最擅长的事。

真实案例速览

案例 规模 AI 辅助效果 来源
SimilarWeb: Spark 作业优化 200 台机器 / 22h 运行 90x 加速(22h→15min),成本降 160x DataFlint 2026
Cisco: Codex 嵌入生产流水线 全球工程团队 月省 1,500+ 工程小时,构建时间 -20% The Applied 2026
Reco.ai: JSONata 引擎重写 JS→Rust, 13K 行代码 7h 完成,年省 $500K AI for Automation 2026
Wix: Airflow 告警 AI Agent 生产级 Airflow 管道 月省 675 工程小时,15% 自动修复率 ZenML 2026

阅读前提(硬条件):

DeepSeek 用户注意:全部可用。本文全程使用 DeepSeek V4-Pro 完成,每个阶段记录 Token 消耗。文末附完整成本对比。

读完能得到什么

  1. 一套 dbt 数据建模的 Claude Code 实操方法------从读现有表结构到设计 Star Schema 到生成可运行的 dbt 模型
  2. Airflow DAG 完整编排------TaskFlow API + TaskGroup + 动态任务 + SLA 监控 + Slack 告警,全部由 Claude Code 生成
  3. PySpark 批处理优化------Claude Code 自动诊断数据倾斜、选择最优 Join 策略、修复 OOM
  4. Great Expectations 数据质量自动化------AI 自动生成 Expectation Suite,覆盖空值/唯一性/分布/引用完整性
  5. 真实数据------每个阶段的 Token 消耗、代码量、人工修改比例
  6. 5 个真实 Debug(DAG 调度冲突、dbt 依赖环、Spark OOM、数据倾斜、GE 误报)

二、项目全景:我们要建什么

2.1 业务背景

一个名为 ShopAnalytix 的电商数据分析平台。业务跑了 14 个月,积累了约 2.7TB 数据------但分析还停留在"运营跑一条 SQL 等 3 分钟,复制到 Excel 做透视表"的阶段。

现有数据资产

复制代码
postgresql://analytics_db/
├── raw_logs/                    # 原始埋点日志(~1.8TB, 日均 4.5GB 增量)
│   ├── access_logs              # 页面访问日志
│   ├── click_events             # 点击事件流
│   └── order_events             # 订单事件流(JSONB)
├── ecommerce/                   # 业务数据库同步(~900GB)
│   ├── orders                   # 订单主表(~50K 行/天)
│   ├── order_items              # 订单明细
│   ├── products                 # 商品信息
│   ├── users                    # 用户信息(~1.2M 注册用户)
│   └── categories               # 类目层级
└── external/                    # 外部数据
    ├── ad_campaigns             # 广告投放数据
    └── inventory_snapshots      # 库存快照

典型痛点

  • 运营想看"过去 7 天各渠道 GMV 趋势"→ 数据分析师手写 SQL 跑 8 分钟 → 导出 Excel 做图 → 第二天数据更新了又要重跑
  • 市场想看"大促期间用户行为漏斗"→ 涉及 5 张表 JOIN,SQL 写了 200 行 → 两周后才交出来
  • 老板想看"库存周转率实时大屏"→ 数据源分散在 3 个系统,没有统一的数据仓库
  • 每次做周报:手工跑 15 条 SQL,复制粘贴到 5 个 Excel Sheet,手动更新图表

2.2 目标架构

复制代码
                          ┌──────────────────────────────────┐
                          │       Metabase BI Dashboard       │
                          └───────────────┬──────────────────┘
                                          │
                          ┌───────────────┴──────────────────┐
                          │         dbt Star Schema           │
                          │   dim_user / dim_product /        │
                          │   dim_date / fact_orders /        │
                          │   fact_pageviews / mart_*         │
                          └───────────────┬──────────────────┘
                                          │
              ┌───────────────────────────┼───────────────────────────┐
              │                           │                           │
              ▼                           ▼                           ▼
    ┌─────────────────┐       ┌─────────────────┐       ┌─────────────────┐
    │  PySpark Batch  │       │  dbt Transform   │       │  Data Quality    │
    │  - 日志清洗      │       │  - SQL+Jinja     │       │  - GE Suites     │
    │  - Sessionization│       │  - 增量/全量     │       │  - 空值/唯一性    │
    │  - 预聚合       │       │  - 物化策略      │       │  - 分布漂移       │
    └────────┬────────┘       └────────┬────────┘       └────────┬────────┘
             │                         │                         │
             └─────────────────────────┼─────────────────────────┘
                                       │
                          ┌────────────┴────────────┐
                          │     Apache Airflow 3.2   │
                          │  DAG 编排 · 调度 · 告警  │
                          └────────────┬────────────┘
                                       │
              ┌────────────────────────┼────────────────────────┐
              │                        │                        │
              ▼                        ▼                        ▼
    ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐
    │  Raw Logs (S3)   │    │  PostgreSQL       │    │  External APIs   │
    │  JSON/Parquet    │    │  业务库同步        │    │  广告/库存       │
    └──────────────────┘    └──────────────────┘    └──────────────────┘

2.3 管道全景

层级 工具 数据形态 调度
Ingest(采集) Airflow DAG 原始 JSON/CSV → Parquet 每小时增量
Process(处理) PySpark 4.1 清洗 → Sessionization → 预聚合 每小时
Transform(转换) dbt-core 1.11 Staging → Intermediate → Marts 每小时
Quality(质量) Great Expectations 1.17 空值/唯一性/分布/引用完整性 每次 dbt run 后
Serve(服务) Metabase BI 看板/Ad-hoc 查询 实时

2.4 工具版本(2026 年 5 月最新)

工具 版本 发布日期
Apache Airflow 3.2.1 2026-04-22
dbt-core 1.11.9 2026-05-06
PySpark 4.1.1 2026-01-09
Great Expectations 1.17.0 2026-05-05

三、阶段一:数据建模------让 Claude Code 读表结构、设计 Star Schema、生成 dbt 模型

3.1 核心策略

数据建模最大的坑不是"不会建",而是"建完后发现漏了业务方真正关心的维度"。Claude Code 在这个阶段的核心价值:一次性读完所有表结构 → 从业务需求反向推导 Star Schema → 自动生成可运行的 dbt 模型文件。传统方式需要 2-3 天的手工分析,Claude Code 一小时内完成。

在项目根目录启动 Claude Code 交互模式:

bash 复制代码
cd shopanalytix && claude

3.2 第一步:全局 Schema 分析

第一条 prompt(Plan 模式,只读):

复制代码
分析 PostgreSQL 数据库中所有表的 Schema 和关系。不要修改任何文件。

任务:
1. 连接 analytics_db,列出所有 schema 下的所有表及字段
2. 分析每个字段的类型、是否可空、是否有索引
3. 通过字段名推断表间关联关系(如 orders.user_id → users.id)
4. 识别可能的数据质量问题(如缺少主键的表、未规范化的 JSONB 字段)
5. 将分析结果写入 docs/SCHEMA_ANALYSIS.md

使用 Read 和 Bash 工具。数据库连接信息在 .env 文件中。

Claude Code 读取了 18 个表的 Schema 后,产出了关键发现:

  • 5 个表缺少主键raw_logs.order_eventsraw_logs.click_eventsexternal.ad_campaigns
  • 3 个 JSONB 字段承载结构化数据order_events.payload(含 23 个嵌套字段)、ad_campaigns.targetingclick_events.properties
  • 隐式外键 14 处 :字段名暗示关联但无数据库级约束(如 order_items.order_id → 无 FK 到 orders.id
  • 2 个表存在字段命名不一致userscreated_atorderscreate_time

3.3 第二步:业务需求 → Star Schema

基于 Schema 分析报告,第二条 prompt:

复制代码
基于 docs/SCHEMA_ANALYSIS.md,设计一个电商分析的 Star Schema 数据仓库。

业务方需要回答的核心问题:
1. 各渠道/类目/时间段的 GMV、订单量、客单价趋势
2. 用户行为漏斗:浏览→加购→下单→支付,各环节转化率
3. 商品库存周转率和滞销预警
4. 广告投放 ROI(按 campaign/channel)
5. 用户分群:RFM 模型(最近购买时间/频率/金额)

输出要求:
1. 维度表设计(dim_*):表名、字段、SCD 策略(Type 1/2)
2. 事实表设计(fact_*):粒度、维度外键、度量字段
3. 每个 dbt 模型的 materialization 策略(table/view/incremental)
4. 数据血缘图(哪个事实表依赖哪些维度表)
5. 输出到 docs/STAR_SCHEMA_DESIGN.md

Claude Code 给出的 Star Schema 设计:

维度表

维度表 来源表 SCD 策略 说明
dim_user ecommerce.users Type 2 用户等级/会员状态可能变化
dim_product ecommerce.products + categories Type 1 商品信息更新即覆盖
dim_date 生成 静态 预生成 2020-2030 日期维度
dim_channel external.ad_campaigns Type 1 渠道映射表
dim_category ecommerce.categories Type 1 类目层级(支持多级)

事实表

事实表 粒度 数据源 物化策略 预估日增量
fact_orders 一行=一个订单 orders + order_items incremental(按 order_date) ~50K 行/天
fact_pageviews 一行=一次页面访问 raw_logs.access_logs incremental(按 event_time) ~2M 行/天
fact_daily_sales 一行=一天/一商品 fact_orders 聚合 table(全量重建) ~5K 行/天
fact_inventory 一行=一天/一商品/一仓库 inventory_snapshots snapshot ~10K 行/天

3.4 第三步:生成 dbt 模型

确认 Star Schema 设计后,第三条 prompt:

复制代码
基于 docs/STAR_SCHEMA_DESIGN.md,生成完整的 dbt 项目。

要求:
1. 按 dbt 最佳实践组织目录结构:models/staging/、models/intermediate/、models/marts/
2. staging 层:从源表做最小清洗(重命名、类型转换、去重)
3. intermediate 层:跨表 JOIN 和业务逻辑
4. marts 层:dim_* 维度表 + fact_* 事实表 + analytics/ 分析聚合
5. 每个模型包含 schema.yml(字段描述 + data tests: unique / not_null / accepted_values / relationships)
6. 使用 Jinja 宏处理重复逻辑(如货币单位统一、渠道归因、RFM 分群)
7. dbt_project.yml 配置 materialization 策略

生成所有文件到 dbt/ 目录。

Claude Code 生成的文件结构:

复制代码
dbt/
├── dbt_project.yml
├── packages.yml                      # dbt_utils + dbt_expectations
├── profiles.yml
├── macros/
│   ├── currency_conversion.sql       # 统一货币换算
│   ├── channel_attribution.sql       # 渠道归因(last-touch)
│   └── rfm_segmentation.sql          # RFM 用户分群
├── models/
│   ├── staging/
│   │   ├── schema.yml
│   │   ├── stg_orders.sql
│   │   ├── stg_order_items.sql
│   │   ├── stg_products.sql
│   │   ├── stg_users.sql
│   │   ├── stg_access_logs.sql
│   │   └── stg_ad_campaigns.sql
│   ├── intermediate/
│   │   ├── schema.yml
│   │   ├── int_order_details.sql     # 订单宽表 JOIN
│   │   ├── int_user_sessions.sql     # 用户会话化视图
│   │   └── int_daily_ad_performance.sql
│   └── marts/
│       ├── dim/
│       │   ├── dim_user.sql
│       │   ├── dim_product.sql
│       │   ├── dim_date.sql
│       │   └── dim_channel.sql
│       ├── fact/
│       │   ├── fact_orders.sql
│       │   ├── fact_pageviews.sql
│       │   └── fact_daily_sales.sql
│       └── analytics/
│           ├── mart_gmv_trend.sql        # GMV 趋势
│           ├── mart_funnel.sql           # 用户行为漏斗
│           ├── mart_rfm_segments.sql     # RFM 分群
│           └── mart_ad_roi.sql           # 广告 ROI
└── tests/
    └── custom/
        └── assert_positive_gmv.sql

关键:Claude Code 生成的是可以直接 dbt run 的代码 ,不是伪代码。每个 .sql 文件都包含完整的 SELECT/CTE/JOIN/WHERE 逻辑。

参考 :dbt Labs 2026 年发布的 dbt-agent-skills(GitHub: dbt-labs/dbt-agent-skills)在 ADE-bench 基准测试中,Claude + Agent Skills 的模型生成准确率达到 53.5%(基线 Claude 为 46.5%)。而 Paradime DinoAI v3.0(基于 Claude 4.6 + 上下文图谱)达到了 88.37%。差距来自"是否连接了实际数据仓库"------让你的 Claude Code 能直接读表结构是提升准确率的关键。

3.5 阶段一数据

指标 数值
Token 消耗 ~35K
DeepSeek V4-Pro 费用 $0.06
耗时 1h 20min
生成文件数 26 个(22 个 .sql + 4 个 .yml)
人工修改 2 处(dim_date 生成逻辑 + ad_campaigns 字段映射)
人工修改比例 ~8%

四、阶段二:ETL 管道------Airflow DAG + dbt 转换 + Great Expectations

4.1 核心策略

ETL 管道的"胶水代码"是数据工程中最耗时、最无聊的部分------写 YAML 配置、拼 DAG 依赖、处理重试逻辑。Claude Code 在这个阶段的价值:一次性生成完整 DAG(含 TaskFlow API + TaskGroup + SLA + Notifier),并自动插入数据质量检查节点

业界基准数据:Markaicode(2026)用 Sonnet 4 批量生成 50 个 Airflow DAG 的首次成功率是 76%,平均生成时间 8 秒,失败主要来自导入错误(18%)和动态 DAG 语法(6%)。

4.2 第一步:生成 Airflow DAG

复制代码
基于 dbt/ 目录的模型,创建 Airflow DAG 编排完整数据管道。

要求:
1. 一个主 DAG:shopanalytix_daily.py,每天凌晨 2:00 UTC 运行
2. DAG 结构使用 TaskGroup:
   - TaskGroup 1: ingest(从 S3/DB 拉取增量数据)
   - TaskGroup 2: spark_process(PySpark 清洗 + Sessionization)
   - TaskGroup 3: dbt_run(staging → intermediate → marts)
   - TaskGroup 4: data_quality(Great Expectations checkpoint + dbt test)
   - TaskGroup 5: notify(成功/失败 → Slack)
3. 使用 TaskFlow API(@task 装饰器,不是传统 Operator)
4. 关键配置:
   - schedule="0 2 * * *"
   - catchup=False
   - is_paused_upon_creation=True(防止部署时误触发回填)
   - max_active_runs=1
   - retries=2, retry_delay=timedelta(minutes=5)
   - SLA: dbt_run 组 30 分钟内完成,total 60 分钟
5. 使用 Airflow 3.x 的 Notifier 抽象做告警(非 on_failure_callback 裸写)
6. 环境变量和连接从 Airflow Variables/Connections 读取

生成文件到 airflow/dags/shopanalytix_daily.py。

Claude Code 生成的 DAG 核心结构:

python 复制代码
# airflow/dags/shopanalytix_daily.py
from airflow.decorators import dag, task, task_group
from airflow.utils.dates import days_ago
from airflow.providers.slack.notifications.slack import (
    send_slack_notification,
    SlackNotifier,
)
from datetime import timedelta, datetime


@dag(
    dag_id="shopanalytix_daily",
    schedule="0 2 * * *",
    start_date=datetime(2026, 1, 1),
    catchup=False,
    is_paused_upon_creation=True,   # 防止部署时误触回填
    max_active_runs=1,
    default_args={
        "retries": 2,
        "retry_delay": timedelta(minutes=5),
    },
    sla_miss_callback=send_slack_notification(
        text=":warning: SLA miss in shopanalytix_daily!"
    ),
    on_failure_callback=SlackNotifier(
        channel="#data-alerts",
        text=":x: shopanalytix_daily FAILED",
    ),
    tags=["shopanalytix", "daily"],
)
def shopanalytix_daily():

    @task_group(group_id="ingest")
    def ingest():
        @task
        def pull_raw_logs():
            """从 S3 拉取增量日志到本地 Parquet"""
            ...

        @task
        def sync_ecommerce_db():
            """增量同步业务库到 staging 区"""
            ...

        @task
        def fetch_external_apis():
            """拉取广告/库存 API 数据"""
            ...

        return [pull_raw_logs(), sync_ecommerce_db(), fetch_external_apis()]

    @task_group(group_id="spark_process")
    def spark_process(inputs):
        @task
        def spark_clean_logs():
            """PySpark 清洗 + sessionize"""
            ...

        @task
        def spark_pre_aggregate():
            """预聚合大表"""
            ...

        return [spark_clean_logs(), spark_pre_aggregate()]

    @task_group(group_id="dbt_run")
    def dbt_run(inputs):
        @task.bash
        def dbt_staging():
            return "cd /opt/dbt && dbt run --select staging --profiles-dir ."

        @task.bash
        def dbt_intermediate():
            return "cd /opt/dbt && dbt run --select intermediate --profiles-dir ."

        @task.bash
        def dbt_marts():
            return "cd /opt/dbt && dbt run --select marts --profiles-dir ."

        dbt_staging() >> dbt_intermediate() >> dbt_marts()

    @task_group(group_id="data_quality")
    def data_quality(inputs):
        @task.bash
        def great_expectations_check():
            return "cd /opt/ge && great_expectations checkpoint run shopanalytix_checkpoint"

        @task.bash
        def dbt_test():
            return "cd /opt/dbt && dbt test --profiles-dir ."

        return [great_expectations_check(), dbt_test()]

    @task_group(group_id="notify")
    def notify(inputs):
        @task
        def send_success():
            """Slack 通知成功 + 数据行数统计"""
            ...

    # 编排
    ingested = ingest()
    processed = spark_process(ingested)
    transformed = dbt_run(processed)
    quality_checked = data_quality(transformed)
    quality_checked >> notify(quality_checked)


dag = shopanalytix_daily()

4.3 第二步:Great Expectations 数据质量

复制代码
为 dbt 模型的 4 张核心表(fact_orders、fact_pageviews、dim_user、mart_gmv_trend)
生成 Great Expectations Expectation Suite。

对每张表自动检测并配置:
1. 空值检查:所有不可为空的字段 → expect_column_values_to_not_be_null
2. 唯一性检查:主键字段 → expect_column_values_to_be_unique
3. 值范围检查:GMV/金额字段 ≥ 0
4. 引用完整性:外键字段引用维度表主键
5. 分布检查:对数值字段生成分位数检查
6. 行数检查:日增量不低于历史 4 周同日均值的 60%(避免固定阈值误报)

生成文件到 great_expectations/expectations/。

Claude Code 自动生成的关键点:它不只是生成 JSON 配置文件,而是在读取了 dbt schema.yml 中的字段定义后 ,根据实际字段语义生成检查规则。例如读到 total_amount DECIMAL(12,2) 会自动加 >= 0 约束,读到 user_id INTEGER NOT NULL 会自动加 not_null + 引用完整性检查。

注意:Great Expectations Cloud 有 ExpectAI(AI 驱动的 Expectation 推荐引擎),但它仅限 GX Cloud(开源 Core 不可用),且存在过度拟合当前数据快照的风险------今天的脏数据可能被奉为明天的验收标准。本教程采用 Claude Code 生成规则 + 人工审核的方式,不走 ExpectAI 自动审批路径。

4.4 阶段二数据

指标 数值
Token 消耗 ~42K
DeepSeek V4-Pro 费用 $0.07
耗时 1h 35min
生成文件数 8 个(1 个 DAG + 5 个 GE Suite + 2 个 Slack 通知模板)
人工修改 3 处(SLA 阈值调整 + GE 分布阈值 + Slack channel 细分)

五、阶段三:PySpark 批处理------让 Claude Code 生成并优化 Join 策略

5.1 核心策略

PySpark 的难点不在 API 本身,而在性能调优 ------同样的逻辑,Join 策略和分区方式不同,性能差 10-100 倍。Claude Code 在这个阶段的核心价值不是"写 PySpark 代码",而是分析数据特征 → 自动选择最优 Join 策略 → 写出带 shuffle/broadcast/partition/salting 优化的代码

业界参考:SimilarWeb 用 AI Copilot(DataFlint)诊断一个在 200 台机器上跑了 22 小时失败的 Spark 作业,发现是非确定性 UDF 触发了重复执行------4 行修复代码将作业从 22h 降到 15min(90x 加速 ),成本从 200 台机器降到 20 台(160x 降本)。

5.2 第一步:Sessionization(用户会话化)

原始日志是逐条的,分析用户行为需要先做 Sessionization------把同一用户 30 分钟内的连续点击合并到一个 Session。

复制代码
写一个 PySpark job 做用户会话化。

数据源:raw_logs.access_logs(Parquet, 日均 ~2M 行, ~4.5GB)
字段:user_id, event_time, page_url, referrer, user_agent, ip_address

逻辑:
1. 按 user_id 分组,按 event_time 排序
2. 如果相邻两次事件间隔 > 30 分钟,切断为新 Session
3. 每个 Session 输出:session_id, user_id, start_time, end_time,
   page_count, entry_page, exit_page, channel(从 referrer 解析)

性能要求:
- 日增量处理时间 < 5 分钟
- 使用 Window 函数 + lag() 做 Session 切割
- 结果按 ds(日期)分区存储为 Parquet

先分析数据特征(user_id 基数、时间跨度、数据倾斜风险),再写代码。

Claude Code 的分析过程:

复制代码
[分析] 读取 access_logs 统计信息...
  - user_id 基数: ~1.2M(高基数,不适合 broadcast)
  - 日均行数: ~2M
  - 数据倾斜: 前 1% 用户(机器人/爬虫)贡献 23% 事件
  - 建议: 加盐(salting)处理倾斜 user_id

[生成] spark/jobs/sessionize_events.py

生成的代码核心逻辑:

python 复制代码
# spark/jobs/sessionize_events.py
from pyspark.sql import SparkSession, Window
from pyspark.sql.functions import (
    col, lag, when, sum as spark_sum, row_number,
    rand, concat, lit
)

spark = SparkSession.builder \
    .appName("ShopAnalytix-Sessionization") \
    .config("spark.sql.adaptive.enabled", "true") \
    .config("spark.sql.adaptive.coalescePartitions.enabled", "true") \
    .config("spark.sql.shuffle.partitions", "400") \
    .getOrCreate()


def sessionize(ds: str):
    """用户行为会话化。ds: 日期分区,格式 YYYY-MM-DD"""
    raw = spark.read.parquet(f"s3://shopanalytix/raw/access_logs/ds={ds}")

    # 1. 加盐处理数据倾斜 ------ 前 1% 用户占 23% 数据
    salted = raw.withColumn(
        "salt", (rand() * 10).cast("int")
    ).withColumn(
        "salted_user_id", concat(col("user_id"), lit("_"), col("salt"))
    )

    # 2. Window 函数 ------ 计算相邻事件时间间隔
    user_window = Window.partitionBy("salted_user_id").orderBy("event_time")
    with_lag = salted.withColumn(
        "prev_event_time", lag("event_time", 1).over(user_window)
    )

    # 3. 超过 30 分钟 = 新 Session
    with_session_flag = with_lag.withColumn(
        "is_new_session",
        when(
            col("prev_event_time").isNull()
            | (col("event_time").cast("long")
               - col("prev_event_time").cast("long") > 1800),
            1
        ).otherwise(0)
    )

    # 4. 累积求和生成 session_id
    session_window = Window.partitionBy("salted_user_id").orderBy("event_time")
    with_session_id = with_session_flag.withColumn(
        "session_id_raw", spark_sum("is_new_session").over(session_window)
    ).withColumn(
        "session_id",
        concat(col("user_id"), lit("_"), lit(ds), lit("_"), col("session_id_raw"))
    )

    # 5. 聚合每个 Session 的首末事件
    session_window_agg = Window.partitionBy("session_id")
    result = with_session_id \
        .withColumn("rn", row_number().over(session_window_agg.orderBy("event_time"))) \
        .filter(col("rn") == 1) \
        .select(
            "session_id", "user_id",
            col("event_time").alias("start_time"),
            # ... 更多字段
        )

    result.write.mode("overwrite").partitionBy("ds").parquet(
        f"s3://shopanalytix/warehouse/sessions/ds={ds}"
    )

5.3 第二步:Spark Join 优化

Session 数据出来后,需要 JOIN 订单数据做转化率分析。但初次运行性能很差。

复制代码
分析 spark/jobs/analyze_conversion.py 中的 JOIN 性能瓶颈。

两张表:
- sessions(~2M 行/天,~8GB)
- orders(~50K 行/天,~200MB)

当前代码用 spark.sql() 写的 JOIN,跑了 12 分钟。

请:
1. 分析数据倾斜情况和 JOIN 策略
2. 识别是否适合 broadcast join
3. 建议最优策略并修改代码
4. 合理解释为什么新策略更快

Claude Code 的分析和修复:

复制代码
[分析] 当前执行计划:
  SortMergeJoin [user_id] ← 两边都有 shuffle,shuffle write ~3.2GB

[发现]
  - orders 表仅 50K 行/天,200MB,完全可放入 driver 内存
  - 但 spark.sql.autoBroadcastJoinThreshold 默认 10MB,不会自动 broadcast
  - sessions 表 user_id 有倾斜

[建议] 调高 autoBroadcastJoinThreshold 到 256MB,让 Spark 自动选择 BHJ
python 复制代码
# 修复前 (SortMergeJoin, 12 min)
df = spark.sql("""
    SELECT s.*, o.order_id, o.total_amount
    FROM sessions s
    JOIN orders o ON s.user_id = o.user_id
    WHERE s.ds = '2026-05-15'
""")

# 修复后 (BroadcastHashJoin, < 3 min)
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", "268435456")  # 256MB
from pyspark.sql.functions import broadcast

df = sessions.alias("s").join(
    broadcast(orders.alias("o")),  # 显式 broadcast
    on="user_id",
    how="left"
).filter(col("s.ds") == "2026-05-15")

5.4 阶段三数据

指标 数值
Token 消耗 ~31K
费用 $0.05
耗时 55 min
生成文件数 2 个 PySpark job
性能提升 SortMergeJoin 12min → BroadcastHashJoin <3min(4x+
人工修改 1 处(广播阈值按集群实际内存调整)

六、阶段四:监控告警------Airflow SLA + dbt 测试 + Slack 告警

6.1 核心策略

数据管道建好后,最大的风险不是"跑不动",而是"跑完了但数据是错的"------而等你发现时下游的报表和决策已经错了三天。Claude Code 在这个阶段的价值:把监控和告警也自动化------一次性生成 SLA 规则、dbt data tests、分级 Slack 通知模板

6.2 第一步:dbt data tests + 自定义测试

复制代码
为所有 dbt 模型添加完整的 data tests。

要求:
1. schema.yml 中每个关键字段至少 1 个 test:
   - 主键:unique + not_null
   - 外键:relationships(引用完整性)
   - 金额/数量:dbt_utils.expression_is_true("amount >= 0")
   - 状态字段:accepted_values
2. 自定义测试:
   - assert_positive_gmv.sql:每日 GMV > 0
   - assert_no_future_dates.sql:所有日期字段 < current_date
   - assert_conversion_rate.sql:转化率在 0-100% 之间
3. 严重性分级:
   - warn:行数偏差 < 20%
   - error:行数偏差 >= 20%、唯一性、引用完整性

修改 dbt/models/**/schema.yml。

6.3 第二步:Airflow SLA + 分级告警

复制代码
完善 Airflow DAG 的监控能力:

1. SLA 阈值:
   - ingest 组: 15 分钟
   - spark_process 组: 10 分钟
   - dbt_run 组: 30 分钟
   - data_quality 组: 10 分钟
   - 总 DAG: 60 分钟

2. 分级告警:
   - SLA miss → Slack #data-alerts + PagerDuty(可能影响下游)
   - dbt test 失败 → Slack #data-quality,附失败 test 列表
   - GE validation 失败 → Slack #data-quality,附 expectation 详情
   - DAG 成功 → Slack #data-notifications(安静模式:仅行数统计摘要)

3. 数据新鲜度监控(独立 DAG):
   - 每日凌晨 6:00 检查前一天分区是否到位
   - 若源表无新数据 → 延迟 30 分钟重试 → 仍无数据 → 升级告警到 #data-alerts

修改 airflow/dags/shopanalytix_daily.py,新增 airflow/dags/shopanalytix_monitor.py。

参考:Wix 工程团队的 AirBot(2026)用 GPT-4o Mini + Claude 4.5 Opus 构建 AI 驱动的 Airflow 告警 Agent,集成 GitHub/Trino/Spark/OpenMetadata 的 MCP 服务器,实现了每月节省 675 工程小时、15% 自动修复率,平均每次交互成本仅 $0.30。

6.4 阶段四数据

指标 数值
Token 消耗 ~22K
费用 $0.04
耗时 50 min
新增文件 3 个(schema.yml 更新 + monitor DAG + Slack 模板)
人工修改 2 处(PagerDuty routing key + Slack channel 细分)

七、成本全记录

7.1 全项目 Token 消耗汇总

阶段 Token DeepSeek V4-Pro 费用 耗时 生成文件 人工修改率
一:数据建模 ~35K $0.06 1h 20min 26 ~8%
二:ETL 管道 ~42K $0.07 1h 35min 8 ~12%
三:PySpark 批处理 ~31K $0.05 55 min 2 ~5%
四:监控告警 ~22K $0.04 50 min 3 ~9%
合计 ~130K $0.22 4h 40min 39 ~8.5%

7.2 传统方式估算对比

阶段 传统估算 AI 辅助实际 加速比
数据建模(Schema 分析 + Star Schema) 2-3 天 1h 20min ~12x
ETL 管道(DAG + dbt + GE) 3-5 天 1h 35min ~18x
PySpark 批处理(含优化) 2-3 天 55 min ~15x
监控告警 1-2 天 50 min ~10x
合计 8-13 天 4h 40min ~16x

7.3 如果用 Claude Opus 4.7

指标 DeepSeek V4-Pro Claude Opus 4.7 倍率
Token 消耗 ~130K ~130K(相同场景) 1x
总费用 $0.22 ~$2.60 11.8x
输出质量 90% 可用的代码 95% 可用的代码 5% 质量差

结论:数据工程场景下(SQL/YAML/Python 胶水代码为主),DeepSeek V4-Pro 的质量完全够用,成本仅为 Opus 的 1/12。


八、复盘:Claude Code 在数据工程中的优劣

做得好的地方

场景 为什么适合 AI 业界验证
YAML/配置文件生成 结构固定、可模板化,AI 填入正确字段基本不会出错 Airflow DAG 首次成功率 76%(Markaicode 2026)
SQL SELECT/JOIN 给定 Schema 后,AI 写出正确 SQL 的准确率极高 dbt + Agent Skills 准确率 53-88%(dbt Labs ADE-bench)
dbt 模型生成 staging → intermediate → marts 层次清晰,AI 照搬模板 72% 数据团队使用 AI 辅助编码(dbt Labs 2026)
数据质量规则 GE expectation 的字段名和约束逻辑高度结构化 ExpectAI 可自动建议规则(但需人工审核)
Airflow DAG 骨架 TaskFlow API 的装饰器模式非常规范,AI 不易偏离 平均 8s 生成一个 DAG,45 行代码

需要人工盯的地方

场景 为什么需要盯 怎么盯
业务逻辑理解 AI 无法自行判断"渠道归因用 last-touch 还是 linear" 在 prompt 中明确业务规则
数据倾斜诊断 AI 能写 salting 代码,但不能直接连 Spark UI 看执行计划 跑完代码后检查 Spark UI 的 Stage 详情
性能阈值设定 SLA 时长、广播阈值、分区数------这些是经验值 按实际数据量调整,记录在 CLAUDE.md
JOIN 正确性验证 AI 的 JOIN ON 条件可能语法正确但语义错误(LEFT vs INNER) 检查 JOIN 前后行数变化
安全/连接串 数据库连接、API Key、Slack webhook------绝不能硬编码 走 Airflow Variables/Connections/Secrets

数据工程 vs 应用开发:AI 效用差异

维度 应用开发(微服务) 数据工程(本文)
代码/配置比 90% 代码 + 10% 配置 40% 代码 + 60% 配置
AI 擅长度 代码生成好,配置容易出错 配置生成极好,SQL 极好
最棘手问题 架构设计 + 分布式一致性 数据倾斜 + 性能调优
AI 最佳角色 主力编码 + 审校 管道搭建 + 质量检查
人的核心价值 架构决策 + Code Review 业务理解 + 性能阈值 + JOIN 语义验证

九、Debug ×5(全项目实际踩坑)

Debug #1 --- DAG 调度冲突:部署后 DAG 疯狂回填两年数据

报错 :Metabase 看板显示 fact_daily_sales 中同一天有 3 条相同聚合数据------DAG 在同一小时跑了 3 次。查看 Airflow DAG Runs 列表,发现从 2024 年 1 月 1 日开始全部补跑。

根因start_date=datetime(2024, 1, 1) + is_paused_upon_creation=False 的组合------虽然 catchup=False,但 is_paused_upon_creation=False 让 Airflow 在 DAG 首次注册时就激活调度器,Airflow 仍从 start_date 计算所有"应该跑但没跑"的实例并排队执行。

场景 start_date is_paused_upon_creation catchup 行为
正确 datetime(2026, 1, 1) True False 首次部署暂停,需手动 unpause
错误 datetime(2024, 1, 1) False False 部署瞬间补跑 2 年数据
修复 datetime(2026, 1, 1) True False 安全

修复

python 复制代码
@dag(
    start_date=datetime(2026, 1, 1),
    catchup=False,
    is_paused_upon_creation=True,  # ← 关键:部署后需手动 unpause
)

验证airflow dags list + 检查 DAG Run 历史------每天只有一次 run。


Debug #2 --- dbt 模型依赖环:int_order_detailsfact_orders 互相 ref

报错

复制代码
Found a cycle: int_order_details -> dim_user -> fact_orders -> int_order_details

根因 :Claude Code 生成的 fact_orders.sql 引用了 int_order_details,而 int_order_details.sql 的 FROM 子句中写了 {``{ ref('fact_orders') }}------两个模型互相引用形成环。dbt 的 DAG 解析器强制单向无环图,编译阶段就报错。

模型 原 ref 实际依赖方向 修复
int_order_details ref('dim_user'), ref('fact_orders') 派生自订单、用户、商品 去掉 ref('fact_orders')
fact_orders ref('int_order_details') 派生自 intermediate 保持不变

关键规则 :dbt 模型的数据流是严格的 staging → intermediate → marts。intermediate 层不应引用 marts 层------这是 AI 最常见的 dbt 错误。

修复int_order_details 只引用 staging 表和 dim 表,不引用 fact 表。加上 dbt doc 注释明确层级。

验证dbt compile 通过 + dbt ls --resource-type model 显示正确的 DAG 顺序。


Debug #3 --- Spark OOM:Executor 内存溢出,YARN 直接 Kill 容器

报错

复制代码
ExecutorLostFailure: executor 5 exited caused by one of the running tasks
Reason: Executor heartbeat timed out.
Container killed by YARN for exceeding memory limits. 9.6 GB of 9 GB used.

根因 :Sessionization job 中 Window.partitionBy("user_id") 导致某个 executor 拿到了超级用户的数据------该用户(爬虫)一天产生 12 万条事件,collect_list() 在窗口内把所有 page_url 塞进数组,单个 task 的内存超过 9GB executor 限制。

Spark OOM 诊断决策树

复制代码
OOM Error
├─ Driver OOM?
│  ├─ collect()/toPandas() 用了? → 限制结果或采样
│  └─ broadcast 表太大? → 增加 driver 内存或禁用 broadcast
└─ Executor OOM? ← 我们的情况
   ├─ Spark UI 有倾斜 Task(max 时长 >> median)? → 加盐拆分热点 key
   ├─ Shuffle 数据量过大? → 增加 shuffle 分区数
   └─ UDF 内存泄漏? → 替换为 Pandas UDF 或内置函数
方案 原理 本场景适用性
spark.sql.shuffle.partitions 增大 更均匀分布 ❌ 无法解决单 key 倾斜
加盐(salting) 拆分大 key 到多个分区 ✅ 最有效
spark.sql.adaptive.skewJoin.enabled Spark 3.2+ 自动检测 ✅ 辅助手段
增大 executor 内存 硬扛 ⚠️ 治标不治本

修复

python 复制代码
# 加盐 ------ 把倾斜最多的 user_id 拆成 10 份
skewed_users = ["bot_crawler_001", "scraper_api_user"]
salted_df = df.withColumn(
    "salted_user_id",
    when(col("user_id").isin(skewed_users),
         concat(col("user_id"), lit("_"), (rand() * 10).cast("int")))
    .otherwise(col("user_id"))
)

验证:Spark UI → Stage 详情 → 每个 task 的 shuffle read size 差异从 800x 降到 8x。


Debug #4 --- 数据倾斜:增量 MERGE 从 3 分钟涨到 45 分钟

症状fact_pageviews 每天增量 MERGE 越来越慢,从最初的 3 分钟到 30 天后跑 45 分钟。每次 MERGE 都扫描全表历史。

根因 :Claude Code 生成的 fact_pageviews 使用了 merge_update_columns 包含所有字段,导致每次 MERGE 需要把增量分区的每一行和全表历史按 unique_key 做匹配------30 天后表里已有 6000 万行,增量 MERGE 开销随表大小线性增长。

策略 适用场景 本场景效果
全表覆盖(table) 小表(<100 万行) ❌ 6000 万行不可行
增量 append-only 不可变日志(如 pageviews) ✅ 每天只 append 新行
增量 + 部分更新 需要修正历史行的表 ✅ MERGE ON ds+PK

修复 :将 fact_pageviews 改为 incremental + append-only 策略(pageview 一旦发生不需要修改历史)。对于需要更新历史行的字段(如用户最后活跃时间),拆分到独立的 dim_user_activity 维表中。

验证:增量运行从 45min 恢复到 3min。


Debug #5 --- Great Expectations 误报:节假日正常流量下降触发告警

症状 :每天凌晨 4:00 GE checkpoint 告警------fact_daily_salesexpect_table_row_count_to_be_between 失败:行数 32,411 低于 min_value=35,000。但那天是法定假日,电商流量下降完全正常。

根因 :Claude Code 自动生成的 GE expectation 用了固定阈值 min_value=35000,没有考虑节假日/周末/大促等周期性波动。GE Cloud 的 ExpectAI 也有相同问题------基于当前数据快照的统计特征生成规则,把"波动"当成了"异常"。

GE 策略 适用场景 本场景问题
固定阈值 稳定的内部系统 ❌ 电商有天然周期性
同比(vs 上周同日) 电商/零售 ✅ 周一 vs 周一更合理
7 日移动平均 ± 30% 去噪 ✅ 能容忍单日波动
节假日特殊规则 电商 ✅ 春节/双11/国庆单独配置

修复:将 GE expectation 改为比较"过去 4 周同日平均":

python 复制代码
# 修复前(固定阈值,易误报)
validator.expect_table_row_count_to_be_between(
    min_value=35000, max_value=100000
)

# 修复后(4 周同日移动平均 ± 30%)
# 使用 GE 的 row_condition + query-based expectation
validator.expect_table_row_count_to_be_between(
    min_value={"$PARAMETER": "rolling_4w_same_day_min"},
    max_value={"$PARAMETER": "rolling_4w_same_day_max"}
)

验证:后续运行------正常周末和节假日波动不再告警,但真实数据缺失(连续 3 天 < 均值 60%)正确触发了升级告警。


十、速查卡

Claude Code 数据工程 Prompt 模板

阶段 模板
Schema 分析 "分析数据库中所有表的 Schema。列出字段类型、索引、隐式外键、数据质量问题。输出 SCHEMA_ANALYSIS.md。只读。"
Star Schema 设计 "基于 Schema 分析,设计 Star Schema。维度表(dim_)+ 事实表(fact_)。标注 SCD 策略和物化策略。"
dbt 模型生成 "基于 Star Schema 设计,生成完整 dbt 项目。staging → intermediate → marts。每个模型含 schema.yml + data tests。"
Airflow DAG "生成 Airflow DAG。TaskFlow API + TaskGroup。含 ingest/spark/dbt/quality/notify 五组。is_paused_upon_creation=True。"
PySpark + 优化 "写 PySpark job 做 {任务}。先分析数据特征(基数/倾斜/大小),再选最优 Join 策略和分区方案。"
数据质量 "为 {表名} 生成 GE Expectation Suite。用滚动窗口(非固定阈值)处理周期性数据。"
监控告警 "为管道添加 SLA + dbt test + Slack/PD 分级告警。warn 和 error 走不同 channel。"

成本控制参数

场景 max_turns max_budget_usd 推荐模型
Schema 分析(只读) 10 0.10 V4-Pro
dbt 模型生成(大量文件) 20 0.30 V4-Pro
PySpark 优化分析 10 0.15 V4-Pro
DAG/YAML 生成 10 0.15 V4-Pro
调试修复 8 0.10 V4-Pro

报错速查

报错 根因 解决
DAG 同一天跑多次 is_paused_upon_creation=False + 远期 start_date is_paused_upon_creation=True
Found a cycle: A → B → A dbt 模型互相 ref,违反单向流 严格 stag → int → marts,底层不 ref 上层
Container killed exceeding memory 单 key 数据倾斜 + Window 全量收集 加盐拆分倾斜 key + AQE skew join
增量 MERGE 越来越慢 merge_update_columns 包含所有列 append-only 策略,可变数据迁移到维表
GE 固定阈值误报 未考虑周期性(周末/节假日波动) 4 周同日移动平均替代固定阈值

CLAUDE.md 数据工程模板

数据工程的 CLAUDE.md 核心要回答五个问题:

  1. 仓库:名称和版本(PostgreSQL 15 / Snowflake / BigQuery)
  2. 转换:dbt 项目结构和模型目录
  3. 编排:Airflow 版本和 DAG 位置
  4. 目录:数据血缘和治理工具(DataHub / OpenMetadata)
  5. BI:最终呈现工具(Metabase / Looker / Mode)

推荐结构(500-1500 字,按实际踩坑逐行增加):

markdown 复制代码
## Naming(最重要的规则)
- staging: stg_<source>__<entity>.sql
- intermediate: int_<entity>_<verb>.sql
- marts: dim_/fact_ 前缀
- 主键: <entity>_id(不是 id 或 uid)

## Testing(强制规则)
- 主键: unique + not_null
- 源表: freshness(1h=warn, 4h=error)
- 事实表外键: relationships 到对应维度表

## Safety Rules(Agent 绝对不能做)
- 永远不在生产环境运行 DROP/TRUNCATE/DELETE
- 始终用 dev target 做探索性工作
- 查询 >1TB 的表必须加分区过滤
- 所有 Agent 发起的查询标记 query_tag = 'claude-code'

## Workflow(Agent 工作流)
1. dbt ls --select +model_name+ 检查影响范围
2. 在正确的层做修改(staging/intermediate/marts)
3. 更新 schema.yml(含字段描述)
4. dbt compile → dbt run → dbt test → sqlfluff lint

扩展阅读

本系列相关文章:


参考文献

  1. dbt Core v1.11 Documentation --- dbt 官方文档,模型/materialization/tests 参考
  2. Apache Airflow 3.2 Documentation --- Airflow 官方文档,DAG/TaskFlow/Notifier 机制
  3. PySpark 4.1 SQL Programming Guide --- Spark SQL + DataFrame API 官方指南
  4. Great Expectations 1.17 Documentation --- GE 官方文档,Expectation/Checkpoint 配置
  5. Kimball Dimensional Modeling Techniques --- Star Schema 设计方法论
  6. dbt Labs: dbt Agent Skills (GitHub) --- dbt 官方 AI Agent 技能包,9 个技能覆盖建模/语义层/排错
  7. Astronomer: AI Agent Tooling for Airflow --- Airflow 官方 AI Agent 工具
  8. dbt Labs: State of Analytics Engineering 2026 --- 72% 数据团队使用 AI 辅助编码
  9. Spark Optimization Guide: Broadcast Join --- Spark 性能调优官方指南
  10. SimilarWeb Case Study: AI Spark Optimization --- 200台机器22h→15min,90x 加速案例
  11. Wix AirBot: AI On-Call Assistant for Airflow --- AI 驱动 Airflow 告警,月省 675 工程小时
  12. Markaicode: AI DAG Generation Benchmark (2026) --- 50 个 DAG 首次成功率 76%
  13. Dataworkers: CLAUDE.md for Data Projects --- 数据工程 CLAUDE.md 最佳实践
相关推荐
AI_yangxi2 小时前
短视频矩阵系统优质厂家
大数据·人工智能·矩阵
代码地平线2 小时前
⭐️C++入门基础精讲(一):从发展历史到第一个程序
大数据·c++·后端·深度学习
Bechamz3 小时前
大数据开发学习Day35
大数据·学习·oracle
fengxin_rou3 小时前
【Kafka 核心概念深度详解】:分区、消费者组、位点及存储消费实战指南
分布式·kafka
Rubin智造社3 小时前
Claude Code开发者大会系列5:如何打造“AI原生工程师”文化
人工智能·开发者大会·ai 原生·claudecode
好赞科技3 小时前
2026年八大上门服务预约小程序:解锁高效生活新体验
大数据·微信小程序
逸Y 仙X3 小时前
文章三十三:Elasticsearch 文本分词器深入实战
java·大数据·elasticsearch·搜索引擎·全文检索
若兰幽竹3 小时前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十四)之【分布式流转】让菜谱“飞”:手机选、平板看、智慧屏播的全场景秘诀
分布式·华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
Yeats_Liao3 小时前
BLE Mesh能承载AI推理吗?分布式边缘AI节点部署实战
服务器·人工智能·分布式·架构·边缘计算