数据工程实战课程 · 编排与治理阶段
dbt是ELT范式的核心工具,让数据分析师用SQL定义转换逻辑在数仓中执行。
# dbt模拟引擎
import sqlite3, time, random, json
from datetime import datetime
from collections import defaultdict
conn = sqlite3.connect(':memory:')
conn.row_factory = sqlite3.Row
c = conn.cursor()
# 创建源表
c.execute('CREATE TABLE raw_orders (id INTEGER PRIMARY KEY, customer_id TEXT, amount REAL, status TEXT, region TEXT, order_date TEXT)')
for i in range(1000):
c.execute("INSERT INTO raw_orders VALUES (?,?,?,?,?,?)",
(i+1, f"CUST_{random.randint(1,200)}", round(random.uniform(10,5000),2),
random.choice(['pending','shipped','delivered','cancelled']),
random.choice(['华东','华南','华北']), datetime.now().strftime('%Y-%m-%d')))
conn.commit()
class dbtModel:
def __init__(self, name, sql, materialized='table', depends_on=None):
self.name = name; self.sql = sql; self.materialized = materialized
self.depends_on = depends_on or []
def execute(self, conn):
start = time.perf_counter()
conn.execute(self.sql)
conn.commit()
ms = (time.perf_counter()-start)*1000
return {'name':self.name,'materialized':self.materialized,'ms':ms}
class dbtProject:
def __init__(self, name):
self.name = name; self.models = []
def add_model(self, model): self.models.append(model)
def run(self):
print(f"dbt run: {self.name}")
executed = set()
for model in self.models:
if all(d in executed for d in model.depends_on):
result = model.execute(conn)
executed.add(model.name)
print(f" ✅ {result['name']} ({result['materialized']}): {result['ms']:.1f}ms")
def test(self):
print(f"dbt test: {self.name}")
tests = [
("unique_raw_orders_id", "SELECT COUNT(*)-COUNT(DISTINCT id) FROM raw_orders"),
("not_null_raw_orders_amount", "SELECT COUNT(*) FROM raw_orders WHERE amount IS NULL"),
("accepted_values_status", "SELECT COUNT(*) FROM raw_orders WHERE status NOT IN ('pending','shipped','delivered','cancelled')"),
]
for name, sql in tests:
result = conn.execute(sql).fetchone()[0]
status = "✅ PASS" if result == 0 else f"❌ FAIL ({result})"
print(f" {name}: {status}")
# 构建dbt项目
project = dbtProject("my_project")
project.add_model(dbtModel("stg_orders",
"CREATE TABLE stg_orders AS SELECT id, customer_id, amount, status, region, order_date FROM raw_orders WHERE status != 'cancelled'",
"table", []))
project.add_model(dbtModel("int_customer_orders",
"CREATE TABLE int_customer_orders AS SELECT customer_id, COUNT(*) as order_count, SUM(amount) as total_amount FROM stg_orders GROUP BY customer_id",
"table", ["stg_orders"]))
project.add_model(dbtModel("fct_daily_sales",
"CREATE TABLE fct_daily_sales AS SELECT order_date, region, COUNT(*) as orders, SUM(amount) as revenue FROM stg_orders GROUP BY order_date, region",
"table", ["stg_orders"]))
project.run()
project.test()
# 查询结果
print("\n客户订单汇总(前5):")
for row in c.execute("SELECT * FROM int_customer_orders ORDER BY total_amount DESC LIMIT 5"):
r = dict(row); print(f" {r['customer_id']}: {r['order_count']}单, ¥{r['total_amount']:,.0f}")
print("✅ 验证通过 - dbt模拟引擎运行正常")
🎁 下一课预告:数据质量!
| 级别 | 特征 | 编排方式 | 治理水平 |
|---|---|---|---|
| L1 | cron+脚本 | 无统一调度 | 无治理 |
| L2 | Airflow/Dbt | DAG编排 | 基本质量检查 |
| L3 | 编排+治理一体 | 自动依赖发现 | 数据目录+血缘 |
| L4 | AI辅助编排 | 自适应调度 | 主动质量治理 |
在生产环境中,我们经常遇到教科书不会告诉你的问题。以下是常见的实战经验和解决方案:
| 指标 | 告警阈值 | 监控方式 |
|---|---|---|
| 管道延迟 | 超过SLA 120% | 端到端时间戳追踪 |
| 数据量偏差 | 日均偏差超过30% | 与历史同期对比 |
| 错误率 | 超过0.1% | 错误计数/总记录数 |
| 数据新鲜度 | 超过SLA 150% | 最新数据时间戳 |
| 资源利用率 | CPU持续>80% | 系统监控 |
A: 根据业务延迟要求决定:秒级用流处理、分钟级用微批、小时级用批处理。大部分场景批处理足够,流处理用于实时业务场景(风控、监控、推荐)。
A: 不会完全取代,但边界在模糊。湖仓一体(如Iceberg/Delta Lake)正在融合两者优势。未来趋势是统一存储+多引擎计算。
A: 先用云原生服务(BigQuery/Snowflake + Fivetran + dbt + Looker),验证业务后再考虑自建。过早优化是万恶之源。
A: 用钱说话:数据质量问题的直接经济损失(错误决策、合规罚款、重复劳动)远大于治理投入。量化问题是第一步。
| 角色 | 职责 | 交付物 |
|---|---|---|
| 数据工程师 | 管道开发与维护 | 数据管道、基础设施 |
| 数据分析师 | 数据分析与报表 | SQL查询、BI报表 |
| 数据科学家 | 模型与实验 | ML模型、实验报告 |
| 数据产品经理 | 需求与优先级 | PRD、数据产品规划 |
| 数据管家 | 数据质量与治理 | 质量规则、数据字典 |