3. 第一个管道:理解 Op 与 Job 的概念

说实话,很多 Dagster 新手一上来就被各种概念搞懵了。什么 Op、Job、Graph、Asset…… 其实没那么复杂。今天我们就从最核心的两个概念入手:Op 和 Job。

我刚开始接触 Dagster 时,也花了点时间才理清它们的关系。说白了,Op 就是管道里的一个最小执行单元,而 Job 就是把这些 Op 串起来的完整流程。你想想看,就像搭积木——Op 是每一块积木,Job 是你搭好的那个模型。

3.1 什么是 Op?

Op 的全称是 Operation,它是 Dagster 中最基本的计算单元。每个 Op 负责完成一个具体的任务,比如读取数据、清洗数据、训练模型等等。

一个 Op 通常包含三部分:

  • 输入:它需要什么数据
  • 计算逻辑:它做什么事
  • 输出:它产生什么结果

我个人习惯把 Op 想象成一个「函数」——有输入、有处理、有输出。只不过在 Dagster 里,它被包装得更规范,方便我们管理和可视化。

3.2 什么是 Job?

Job 就是 一组 Op 的有序组合。它定义了 Op 之间的依赖关系和执行顺序。

举个例子:

  • Op A 负责下载数据
  • Op B 负责清洗数据
  • Op C 负责分析数据

Job 会告诉 Dagster:先跑 A,再跑 B,最后跑 C。而且如果 B 依赖 A 的输出,Job 会自动帮你处理好数据传递。

核心区别一句话总结:

Op 是「做什么」,Job 是「按什么顺序做」。

3.3 编写第一个 Hello World Op

好了,理论说完了,我们直接上手写代码。这是你 Dagster 生涯的第一个 Op,我建议你亲手敲一遍,别复制粘贴。

from dagster import op

@op
def hello_world():
    """
    我的第一个 Dagster Op
    功能:打印一句问候
    """
    message = "Hello, Dagster!"
    print(message)
    return message

嗯,就这么简单。这个 Op 没有输入,只有一个输出——它返回了一个字符串。

你可能会问:「就这?」对,就这。Dagster 的 Op 装饰器 @op 把一个普通函数变成了一个可被 Dagster 管理的计算单元。

小提示:Op 的函数名就是它在 Dagit 中显示的名字。所以命名时尽量用有意义的名称,别用 op1、op2 这种。

3.4 将 Op 组装成 Job

有了 Op,下一步就是把它装进 Job 里。Job 的写法也很直观:

from dagster import Job

hello_job = Job(name="hello_world_job", ops=[hello_world])

或者用装饰器的方式:

@job
def hello_job():
    hello_world()

两种写法效果一样。我个人更推荐第二种——装饰器方式,因为它更接近我们写 Python 函数的习惯,而且后续扩展多个 Op 时更清晰。

这里有个细节要注意:Job 里的 Op 调用顺序就是执行顺序。如果你有多个 Op,Dagster 会按照你在 Job 函数体里写的顺序依次执行。

3.5 在 Dagit 中可视化运行

代码写完了,怎么看到效果?Dagster 提供了一个 Web UI 叫 Dagit,你可以在里面可视化你的管道。

首先,把代码保存到一个 Python 文件中,比如 hello_dagster.py:

from dagster import op, job

@op
def hello_world():
    message = "Hello, Dagster!"
    print(message)
    return message

@job
def hello_job():
    hello_world()

然后在终端运行:

dagit -f hello_dagster.py

打开浏览器,访问 http://localhost:3000。你会看到 Dagit 的界面,左侧是代码位置,右侧是管道视图。

点击 Launchpad 标签页,选择 hello_job,然后点击右下角的 Launch Run 按钮。Dagit 就会执行你的 Job,并在右侧显示运行日志。

注意:我第一次用 Dagit 时,点了 Launch Run 后等了好久没反应。后来发现是忘了启动 Dagit 的守护进程。确保终端窗口一直开着,别关掉。

3.6 理解 Op 与 Job 的关系图

为了让你更直观地理解 Op 和 Job 的关系,我画了一张图:

Op 与 Job 的关系 Job: hello_job Op A 下载数据 Op B 清洗数据 Op C 分析数据 Op 是积木块,Job 是搭好的模型 Job 定义了 Op 的执行顺序和数据流向

从图中你可以看到:

  • Job 是一个容器,里面装着多个 Op
  • Op 之间通过箭头表示依赖关系
  • Job 负责协调 Op 的执行顺序

3.7 常见问题与避坑

问题 原因 解决方法
Dagit 启动后看不到 Job 文件路径或代码格式错误 检查 dagit -f 指向的文件是否存在,代码是否有语法错误
点击 Launch Run 没反应 Dagit 守护进程未运行 保持终端窗口打开,不要关闭
Op 执行报错 函数内部逻辑错误 查看 Dagit 中的运行日志,定位具体错误行

我的经验:刚开始写 Dagster 管道时,别追求复杂。先从一个 Op 一个 Job 开始,跑通了再慢慢加东西。我曾经一上来就想写个完整的 ETL 管道,结果调试了整整一天……后来学乖了,每次只加一个 Op,跑通再继续。

3.8 本章小结

今天我们做了三件事:

  1. 理解了 Op 是 Dagster 的最小执行单元
  2. 理解了 Job 是 Op 的有序组合
  3. 亲手写了一个 Hello World Op 并组装成 Job,在 Dagit 中运行成功

别小看这个简单的例子。你想想看,任何复杂的数据管道,本质上都是一个个 Op 拼起来的。掌握了 Op 和 Job,你就掌握了 Dagster 的基石。