本文目录导读:

我来详细介绍如何用Python构建高效稳定的数据体系。
数据体系架构设计
核心架构组件
# 1. 数据分层架构
from dataclasses import dataclass
from typing import Optional, Any
import logging
@dataclass
class DataLayer:
"""数据分层定义"""
raw: str = "raw" # 原始数据层
staging: str = "staging" # 清洗层
dwd: str = "dwd" # 明细层
dim: str = "dim" # 维度层
dws: str = "dws" # 汇总层
app: str = "app" # 应用层
class DataPipeline:
"""数据管道基类"""
def __init__(self, config: dict):
self.config = config
self.logger = logging.getLogger(__name__)
self.error_handler = ErrorHandler()
def extract(self):
"""数据提取"""
raise NotImplementedError
def transform(self, data):
"""数据转换"""
raise NotImplementedError
def load(self, data):
"""数据加载"""
raise NotImplementedError
def run(self):
"""运行管道"""
try:
data = self.extract()
transformed = self.transform(data)
self.load(transformed)
self.error_handler.succeed()
except Exception as e:
self.error_handler.fail(e)
raise
数据采集层实现
多源数据采集
import pandas as pd
from sqlalchemy import create_engine
import redis
from kafka import KafkaConsumer
import asyncio
import aiohttp
from typing import AsyncGenerator
class DataCollector:
"""多源数据采集器"""
def __init__(self, config: dict):
self.config = config
self.engines = {}
self.cache = redis.Redis(
host=config['redis_host'],
port=config['redis_port'],
decode_responses=True
)
def collect_from_mysql(self, query: str, conn_id: str) -> pd.DataFrame:
"""从MySQL采集数据"""
if conn_id not in self.engines:
self.engines[conn_id] = create_engine(
f"mysql+pymysql://{self.config['mysql_user']}:"
f"{self.config['mysql_pass']}@{self.config['mysql_host']}/"
f"{self.config['mysql_db']}?charset=utf8mb4"
)
return pd.read_sql(query, self.engines[conn_id])
async def collect_from_api(self, url: str, params: dict) -> dict:
"""异步采集API数据"""
async with aiohttp.ClientSession() as session:
async with session.get(url, params=params) as response:
return await response.json()
def collect_from_kafka(self, topic: str, group_id: str):
"""采集Kafka流数据"""
consumer = KafkaConsumer(
topic,
bootstrap_servers=self.config['kafka_servers'],
group_id=group_id,
auto_offset_reset='earliest'
)
for message in consumer:
yield message.value
数据质量保障
质量监控和校验
from pydantic import BaseModel, validator
import great_expectations as ge
from datetime import datetime
class DataQualityRule(BaseModel):
"""数据质量规则定义"""
rule_name: str
column: str
rule_type: str # not_null, unique, range, pattern
params: dict = {}
@validator('rule_type')
def validate_rule_type(cls, v):
valid_types = ['not_null', 'unique', 'range', 'pattern', 'custom']
if v not in valid_types:
raise ValueError(f'Invalid rule type: {v}')
return v
class DataQualityChecker:
"""数据质量检查器"""
def __init__(self):
self.rules = []
self.quality_metrics = {}
def add_rule(self, rule: DataQualityRule):
"""添加质量规则"""
self.rules.append(rule)
def check_dataframe(self, df: pd.DataFrame) -> dict:
"""检查DataFrame质量"""
results = {
'passed': True,
'violations': [],
'metrics': {}
}
for rule in self.rules:
if rule.rule_type == 'not_null':
null_count = df[rule.column].isnull().sum()
if null_count > 0:
results['violations'].append({
'rule': rule.rule_name,
'column': rule.column,
'null_count': null_count
})
elif rule.rule_type == 'unique':
dup_count = df[rule.column].duplicated().sum()
if dup_count > 0:
results['violations'].append({
'rule': rule.rule_name,
'column': rule.column,
'duplicate_count': dup_count
})
results['passed'] = len(results['violations']) == 0
results['metrics']['total_rows'] = len(df)
results['metrics']['timestamp'] = datetime.now()
return results
def generate_quality_report(self):
"""生成质量报告"""
report = {
'total_checks': len(self.rules),
'passed_checks': 0,
'failed_checks': 0,
'detailed_results': []
}
for rule in self.rules:
result = self.check_rule(rule)
if result['passed']:
report['passed_checks'] += 1
else:
report['failed_checks'] += 1
report['detailed_results'].append(result)
return report
数据处理优化
高性能数据处理
import numpy as np
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import dask.dataframe as dd
from functools import lru_cache
class PerformanceOptimizer:
"""性能优化器"""
def __init__(self):
self.executor = ProcessPoolExecutor(max_workers=4)
self.cache_size = 128
@lru_cache(maxsize=128)
def get_cached_data(self, query: str):
"""缓存查询结果"""
return self.execute_query(query)
def parallel_process(self, data: list, func: callable) -> list:
"""并行处理数据"""
with ThreadPoolExecutor(max_workers=8) as executor:
results = list(executor.map(func, data))
return results
def chunk_processing(self, df: pd.DataFrame, func: callable,
chunk_size: int = 10000):
"""分块处理大数据"""
chunks = np.array_split(df, len(df) // chunk_size + 1)
for chunk in chunks:
yield func(chunk)
class MemoryOptimizer:
"""内存优化器"""
@staticmethod
def optimize_dtypes(df: pd.DataFrame) -> pd.DataFrame:
"""优化数据类型以节省内存"""
for col in df.columns:
col_type = df[col].dtype
if col_type != 'object':
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif str(col_type)[:5] == 'float':
if c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
# 对字符串列进行类别编码
if df[col].nunique() / len(df) < 0.5:
df[col] = df[col].astype('category')
return df
容错与恢复机制
错误处理和恢复
import time
from tenacity import retry, stop_after_attempt, wait_exponential
class ErrorHandler:
"""错误处理器"""
def __init__(self):
self.error_log = []
self.recovery_strategies = {}
def register_recovery(self, error_type: type, strategy: callable):
"""注册恢复策略"""
self.recovery_strategies[error_type] = strategy
def handle_error(self, error: Exception, context: dict = None):
"""处理错误并尝试恢复"""
error_info = {
'timestamp': datetime.now(),
'error_type': type(error).__name__,
'error_message': str(error),
'context': context
}
self.error_log.append(error_info)
# 查找恢复策略
for error_type, strategy in self.recovery_strategies.items():
if isinstance(error, error_type):
return strategy(error, context)
# 默认恢复:重试
return self.default_recovery(error)
@retry(stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10))
def default_recovery(self, error):
"""默认恢复策略:重试"""
raise error
class DataBackup:
"""数据备份恢复"""
def __init__(self, backup_path: str):
self.backup_path = backup_path
def create_snapshot(self, data: pd.DataFrame, snapshot_name: str):
"""创建数据快照"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filepath = f"{self.backup_path}/{snapshot_name}_{timestamp}.parquet"
data.to_parquet(filepath, compression='snappy')
return filepath
def restore_snapshot(self, snapshot_path: str) -> pd.DataFrame:
"""恢复数据快照"""
return pd.read_parquet(snapshot_path)
监控与告警
系统监控
import psutil
import json
from datetime import datetime, timedelta
class SystemMonitor:
"""系统监控器"""
def __init__(self, alert_thresholds: dict = None):
self.thresholds = alert_thresholds or {
'cpu_percent': 80,
'memory_percent': 85,
'disk_percent': 90
}
self.metrics_history = []
def collect_metrics(self):
"""收集系统指标"""
metrics = {
'timestamp': datetime.now(),
'cpu_percent': psutil.cpu_percent(interval=1),
'memory_percent': psutil.virtual_memory().percent,
'disk_percent': psutil.disk_usage('/').percent,
'network_io': psutil.net_io_counters()._asdict()
}
self.metrics_history.append(metrics)
return metrics
def check_alerts(self):
"""检查是否需要告警"""
current = self.collect_metrics()
alerts = []
for metric, threshold in self.thresholds.items():
if current[metric] > threshold:
alerts.append({
'metric': metric,
'current_value': current[metric],
'threshold': threshold,
'severity': 'warning' if current[metric] < threshold * 1.2 else 'critical'
})
return alerts
def generate_health_report(self):
"""生成健康报告"""
metrics = self.collect_metrics()
alerts = self.check_alerts()
return {
'status': 'healthy' if len(alerts) == 0 else 'unhealthy',
'metrics': metrics,
'alerts': alerts,
'recommendations': self._generate_recommendations(metrics)
}
def _generate_recommendations(self, metrics: dict) -> list:
"""生成优化建议"""
recommendations = []
if metrics['cpu_percent'] > 70:
recommendations.append("考虑增加计算资源或优化算法")
if metrics['memory_percent'] > 80:
recommendations.append("建议清理内存或增加内存容量")
if metrics['disk_percent'] > 85:
recommendations.append("建议清理磁盘空间或扩展存储")
return recommendations
架构最佳实践
完整示例:电商数据体系
class EcommerceDataPipeline:
"""电商数据管道示例"""
def __init__(self, config: dict):
self.config = config
self.collector = DataCollector(config)
self.quality_checker = DataQualityChecker()
self.monitor = SystemMonitor()
self.backup = DataBackup(config['backup_path'])
# 配置质量规则
self._setup_quality_rules()
def _setup_quality_rules(self):
"""设置质量规则"""
rules = [
DataQualityRule(
rule_name="订单ID非空",
column="order_id",
rule_type="not_null"
),
DataQualityRule(
rule_name="用户ID唯一",
column="user_id",
rule_type="unique"
)
]
for rule in rules:
self.quality_checker.add_rule(rule)
async def run_daily_pipeline(self):
"""运行每日数据管道"""
try:
# 1. 采集数据
orders = self.collector.collect_from_mysql(
"SELECT * FROM orders WHERE date = CURRENT_DATE",
"order_db"
)
# 2. 质量检查
quality_check = self.quality_checker.check_dataframe(orders)
if not quality_check['passed']:
self._handle_quality_issues(quality_check)
return
# 3. 数据备份
self.backup.create_snapshot(orders, "orders_daily")
# 4. 数据转换
transformed = self._transform_orders(orders)
# 5. 加载到数据仓库
self._load_to_warehouse(transformed)
# 6. 监控和告警
health = self.monitor.generate_health_report()
if health['status'] != 'healthy':
self._send_alerts(health['alerts'])
except Exception as e:
self._handle_pipeline_error(e)
def _transform_orders(self, orders: pd.DataFrame) -> pd.DataFrame:
"""订单数据转换"""
# 数据清洗和转换逻辑
orders['order_date'] = pd.to_datetime(orders['order_date'])
orders['amount_normalized'] = orders['amount'].fillna(0)
orders['customer_segment'] = orders['total_amount'].apply(
lambda x: 'high' if x > 1000 else 'medium' if x > 500 else 'low'
)
return orders
def _load_to_warehouse(self, data: pd.DataFrame):
"""加载到数据仓库"""
engine = create_engine(self.config['warehouse_conn'])
data.to_sql(
'fact_orders',
engine,
if_exists='append',
index=False,
method='multi',
chunksize=10000
)
配置管理
import yaml
from pathlib import Path
class ConfigManager:
"""配置管理器"""
def __init__(self, config_path: str):
self.config_path = Path(config_path)
self.config = self._load_config()
def _load_config(self) -> dict:
"""加载配置"""
with open(self.config_path, 'r') as f:
return yaml.safe_load(f)
def get_database_config(self, db_name: str) -> dict:
"""获取数据库配置"""
return self.config['databases'].get(db_name, {})
def get_pipeline_config(self, pipeline_name: str) -> dict:
"""获取管道配置"""
return self.config['pipelines'].get(pipeline_name, {})
部署与运维
# Docker化部署配置文件示例
"""
version: '3.8'
services:
data-pipeline:
build: .
environment:
- PYTHONUNBUFFERED=1
- LOG_LEVEL=INFO
volumes:
- ./data:/app/data
- ./logs:/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "from app import health; health.check()"]
interval: 30s
timeout: 10s
retries: 3
"""
- 架构分层:清晰的数据分层(ODS、DWD、DWS、ADS)
- 错误处理:完善的异常捕获和恢复机制
- 性能优化:并行处理、内存优化、缓存策略
- 数据质量:自动化的质量检查和告警
- 监控告警:实时监控系统健康状态
- 备份恢复:定期快照和故障恢复
- 配置管理:外部化配置,环境分离
- 日志记录:全面的日志追踪
这个框架可以根据实际业务需求进行调整和扩展,确保数据体系的稳定性和高效性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播