# 导入 sleep,用于模拟模型训练所需的时间 from time import sleep # 导入 DAG,用于定义 Airflow 工作流 from airflow import DAG # 导入 PythonOperator,用于执行 Python 函数 from airflow.operators.python import PythonOperator # 导入 datetime,用于设置 DAG 的开始日期 from datetime import datetime # 导入 random,用于生成随机准确率 import random # ==================== 1. 模拟模型训练任务 ==================== def train_model(model_name, **context): """ 模拟训练一个机器学习模型,并将模型准确率存入 XCom。 model_name:模型名称,例如 model_A、model_B、model_C **context:Airflow 传入的运行上下文,其中包含 ti 等信息 """ # 模拟模型训练过程,让当前任务等待 10 秒 sleep(10) # 随机生成一个 0.7 到 1.0 之间的浮点数,模拟模型准确率 accuracy = random.uniform(0.7, 1.0) # 将模型准确率手动推送到 XCom # key='model_accuracy':这条数据在 XCom 中的键名 # value=accuracy:实际保存的准确率 context['ti'].xcom_push( key='model_accuracy', value=accuracy ) # 将模型名称和准确率输出到任务日志中 print(f'{model_name} accuracy: {accuracy}') # 注意:这里没有 return accuracy # 因此不会把 accuracy 作为函数返回值保存到默认的 return_value 中 # ==================== 2. 选择最佳模型 ==================== def choose_best_model(**context): """ 从三个训练任务的 XCom 中读取准确率,并找出准确率最高的模型。 """ # 获取当前任务实例 TaskInstance ti = context['ti'] # 一次性读取三个上游任务的准确率 accuracies = ti.xcom_pull( task_ids=['model_A', 'model_B', 'model_C'], # 指定要读取的任务 key='model_accuracy' # 指定要读取的 XCom 键 ) # 输出读取到的准确率列表 # 例如:[0.82, 0.95, 0.88] print(f'accuracies: {accuracies}') # 找出列表中的最大准确率 # max(accuracies) 返回最大值,例如 0.95 # accuracies.index(...) 返回该值第一次出现的索引,例如 1 best_model_index = accuracies.index(max(accuracies)) # 输出最高准确率 # 注意:这里原代码通过索引拼出了 model_1、model_2 或 model_3, # 并不是实际任务 ID model_A、model_B 或 model_C。 print( f'Best model accuracy: {accuracies[best_model_index]} ' f'from model_{best_model_index + 1}' ) # ==================== 3. 定义 DAG 工作流 ==================== with DAG( # DAG 的唯一标识符 dag_id='xcom_example2', # DAG 的开始日期;不代表当天一定会自动执行 start_date=datetime(2024, 10, 1), # 不设置定时调度,通常需要手动触发 DAG schedule_interval=None, # 不补跑历史上未执行的调度任务 catchup=False, # 为 DAG 添加标签,便于在 Airflow 页面中筛选 tags=["demo"] ) as dag: # ==================== 4. 定义模型 A 训练任务 ==================== model_A = PythonOperator( # Airflow 中的任务 ID task_id='model_A', # 指定要执行的 Python 函数 python_callable=train_model, # 向 train_model 函数传递额外参数 # 相当于调用 train_model(model_name='model_A', ...) op_kwargs={'model_name': 'model_A'} ) # ==================== 5. 定义模型 B 训练任务 ==================== model_B = PythonOperator( task_id='model_B', python_callable=train_model, op_kwargs={'model_name': 'model_B'} ) # ==================== 6. 定义模型 C 训练任务 ==================== model_C = PythonOperator( task_id='model_C', python_callable=train_model, op_kwargs={'model_name': 'model_C'} ) # ==================== 7. 定义最佳模型选择任务 ==================== choose_task = PythonOperator( # 任务 ID task_id='choose_best_model', # 指定执行选择最佳模型的函数 python_callable=choose_best_model ) # ==================== 8. 设置任务依赖关系 ==================== # 三个模型任务互相没有依赖关系,可以并行执行 # choose_task 必须等待三个模型任务全部成功完成后才会执行 [model_A, model_B, model_C] >> choose_task # 脚本被直接执行时,调用 DAG 的 CLI 入口 # 这是旧式的命令行调试写法,不是部署 DAG 必需的内容; # 正常使用 Airflow 调度器时,通常可以删除这段代码。 if __name__ == '__main__': dag.cli()