实战项目

第23课:推荐数据管道

数据工程实战课程 · 实战项目阶段

🎯 推荐数据管道

构建推荐系统数据管道,从用户行为收集到特征工程到训练数据准备。

🐍 Python实战:核心实战

# 推荐数据管道
import random, time
from datetime import datetime
from collections import defaultdict

class UserBehaviorCollector:
    def __init__(self): self.events = []
    def collect(self, user_id, item_id, action, timestamp=None):
        self.events.append({'user_id':user_id,'item_id':item_id,'action':action,'ts':timestamp or datetime.now().isoformat()})
        return len(self.events)

class FeatureEngine:
    def __init__(self): self.user_features = defaultdict(dict); self.item_features = defaultdict(dict)
    def compute_user_features(self, events):
        user_stats = defaultdict(lambda: {'views':0,'clicks':0,'purchases':0,'categories':defaultdict(int)})
        for e in events:
            uid = e['user_id']
            if e['action'] == 'view': user_stats[uid]['views'] += 1
            elif e['action'] == 'click': user_stats[uid]['clicks'] += 1
            elif e['action'] == 'purchase': user_stats[uid]['purchases'] += 1
            user_stats[uid]['categories'][e['item_id'][:3]] += 1
        for uid, stats in user_stats.items():
            self.user_features[uid] = {
                'total_actions': stats['views']+stats['clicks']+stats['purchases'],
                'ctr': round(stats['clicks']/max(stats['views'],1), 3),
                'conv_rate': round(stats['purchases']/max(stats['clicks'],1), 3),
                'top_category': max(stats['categories'], key=stats['categories'].get) if stats['categories'] else 'none',
                'is_active': stats['views'] > 5
            }
    def compute_item_features(self, events):
        item_stats = defaultdict(lambda: {'views':0,'clicks':0,'purchases':0,'revenue':0})
        for e in events:
            iid = e['item_id']
            if e['action'] == 'view': item_stats[iid]['views'] += 1
            elif e['action'] == 'click': item_stats[iid]['clicks'] += 1
            elif e['action'] == 'purchase':
                item_stats[iid]['purchases'] += 1
                item_stats[iid]['revenue'] += random.uniform(10, 200)
        for iid, stats in item_stats.items():
            self.item_features[iid] = {
                'popularity': stats['views'],
                'ctr': round(stats['clicks']/max(stats['views'],1), 3),
                'conv_rate': round(stats['purchases']/max(stats['clicks'],1), 3),
                'total_revenue': round(stats['revenue'], 2)
            }

class SampleGenerator:
    def __init__(self): self.samples = []
    def generate(self, events):
        user_items = defaultdict(set)
        for e in events:
            if e['action'] == 'purchase': user_items[e['user_id']].add(e['item_id'])
        for uid, items in user_items.items():
            for item in items: self.samples.append({'user_id':uid,'item_id':item,'label':1})
            # Negative sampling
            all_items = set(e['item_id'] for e in events)
            neg = list(all_items - items)[:min(3, len(all_items)-len(items))]
            for item in neg: self.samples.append({'user_id':uid,'item_id':item,'label':0})

# 运行
collector = UserBehaviorCollector()
categories = ['CAT_A','CAT_B','CAT_C']
actions = ['view','click','purchase']
for _ in range(2000):
    uid = f"U{random.randint(1,200)}"
    iid = f"{random.choice(categories)}_{random.randint(1,50)}"
    action = random.choices(actions, weights=[0.6,0.3,0.1])[0]
    collector.collect(uid, iid, action)

feature_engine = FeatureEngine()
feature_engine.compute_user_features(collector.events)
feature_engine.compute_item_features(collector.events)

sample_gen = SampleGenerator()
sample_gen.generate(collector.events)

print("推荐数据管道:")
print(f"  行为事件: {len(collector.events)}")
print(f"  用户特征: {len(feature_engine.user_features)}")
print(f"  物品特征: {len(feature_engine.item_features)}")
print(f"  训练样本: {len(sample_gen.samples)} (正例{sum(1 for s in sample_gen.samples if s['label']==1)})")
sample_user = list(feature_engine.user_features.items())[0]
print(f"  用户示例: {sample_user[0]} → {sample_user[1]}")
print("✅ 验证通过 - 推荐数据管道运行正常")
💡 实战建议:动手实现本课代码示例,修改参数观察输出变化。生产环境还需考虑错误处理、监控告警和数据安全。

🎯 特征工程管道

  1. 统计/序列/Embedding特征
  2. 特征版本管理

🎯 A/B测试框架

  1. 流量分配
  2. 指标计算

🏆 第23课成就解锁

🎁 下一课预告:数据治理平台!

📖 原理深入:企业数据平台架构

数据平台核心架构原则

  1. 分层解耦:采集层、存储层、处理层、服务层各司其职
  2. 存储计算分离:存储和计算独立扩展
  3. 数据契约:生产者和消费者通过Schema契约解耦
  4. 自助服务:数据消费者能自助发现、理解和使用数据
  5. 可观测性:全链路监控、追踪和告警

平台建设路线图

阶段目标关键能力周期
MVP基础数据流转ETL+数仓+报表1-3月
成长期数据自助自助分析+流处理+治理3-6月
成熟期数据驱动实时+ML+数据产品6-12月
领先期数据创新AI+自动化+货币化12月+

🏆 最佳实践:数据平台建设检查清单

🔬 深度案例:生产环境实战经验

踩坑与解决方案

在生产环境中,我们经常遇到教科书不会告诉你的问题。以下是常见的实战经验和解决方案:

监控与运维指标

指标告警阈值监控方式
管道延迟超过SLA 120%端到端时间戳追踪
数据量偏差日均偏差超过30%与历史同期对比
错误率超过0.1%错误计数/总记录数
数据新鲜度超过SLA 150%最新数据时间戳
资源利用率CPU持续>80%系统监控
⚠️ 常见反模式
💡 架构演进建议:不要一开始就追求完美架构。从MVP开始,随业务增长逐步演进。每次演进都要回答三个问题:当前瓶颈是什么?解决它的投入产出比如何?是否为后续扩展留了空间?

📚 延伸阅读与参考

推荐资源

🤔 常见问题与解答

Q1: 如何选择批处理还是流处理?

A: 根据业务延迟要求决定:秒级用流处理、分钟级用微批、小时级用批处理。大部分场景批处理足够,流处理用于实时业务场景(风控、监控、推荐)。

Q2: 数据湖会取代数据仓库吗?

A: 不会完全取代,但边界在模糊。湖仓一体(如Iceberg/Delta Lake)正在融合两者优势。未来趋势是统一存储+多引擎计算。

Q3: 初创公司如何选择数据技术栈?

A: 先用云原生服务(BigQuery/Snowflake + Fivetran + dbt + Looker),验证业务后再考虑自建。过早优化是万恶之源。

Q4: 如何说服业务方投资数据治理?

A: 用钱说话:数据质量问题的直接经济损失(错误决策、合规罚款、重复劳动)远大于治理投入。量化问题是第一步。

性能调优实战技巧

数据工程团队协作模式

角色职责交付物
数据工程师管道开发与维护数据管道、基础设施
数据分析师数据分析与报表SQL查询、BI报表
数据科学家模型与实验ML模型、实验报告
数据产品经理需求与优先级PRD、数据产品规划
数据管家数据质量与治理质量规则、数据字典
💡 职业发展建议:数据工程是一个快速发展的领域。保持学习的关键是:1)理解原理而非仅会工具;2)动手实践而非仅看文档;3)关注社区动态,了解最新趋势;4)建立个人项目,积累实战经验。