BLOGE
0.9.9-RC1在线版 · 编制 2026-11-02 · English
第 4 章 —— 流动的数据
承诺: 读完本章后,你会理解数据如何进入、穿 过并离开一个 BLOGE graph;同时你也会知道什么时候该用 input binding、什么时候该用 transform、什么时候必须写成 operator。
学习目标
- 解释
input块中可用的三类数据来源:context 值、上游输出 和 字面量。 - 使用 路径表达式 访问嵌套字段,包括安全导航(
?.)和空值合并(??)。 - 用 下标访问 读取列表与映射元素(
xs[i]、xs?[i]、xs[-1]、m["key"]),并在表达式结果上使用 动态成员访问((expr).field、(expr)?.field)。 - 区分 transform(不调度 Operator 的数据投影)与 operator node(可独立调度的业务逻辑)。
- 在输入绑定中使用 lambda 表达式 做集合操作(
map、filter、reduce)。
前置条件
源示例
| 文件 | 展示内容 |
|---|---|
order-enrichment-lambda.bloge | 在输入绑定中使用 lambda 做集合处理 |
order-summary-index-access.bloge | 下标访问、负索引与动态成员访问 |
basic.bloge (transform) | 最小 transform 块 |
safe-navigation.bloge | 安全导航 ?. 与空值合并 ?? |
lambda-map.bloge | 在输入绑定里使用 map |
order-process.bloge | 真实工作流里的 transform |
为什么这很重要
第 3 章里你学到的是“依赖决定什么时候运行”。但依赖只决定 何时,不决定 拿到什么数据。
数据流设计得好,graph 会清晰、易维护;数据流设计得差,每个节点都在做额外的字段搬运和结构重塑,最后谁也说不清每一步真正的业务职责是什么。
BLOGE 为数据处理提供了分层工具:
| 层次 | 工具 | 调度成本 | 适用场景 |
|---|---|---|---|
| 路由 | Input binding(input { … }) | 无 —— 在装配阶段求值 | 传递 context 字段或上游输出 |
| 投影 | Transform(transform { … }) | 无 —— 虚拟节点,不调度 operator | 重组、重命名字段,但不包含业务逻辑 |
| 计算 | Operator node(node … : Op { … }) | 完整调度成本 | 业务逻辑、I/O、副作用 |
选对层次,graph 才能既快又好读。
心智模型
- Input bindings 从
ctx或someNode.output.field取值。 - Transforms 是虚拟的——引擎不会为它们单独开线程去调度。
- Operator nodes 才是真正执行代码的单元,因而会附带 timeout、retry、fallback 等运行时语义。
第一个可运行示例
Input bindings —— 基础形式
每个 input { … } 都是一组 key-value 绑定。右侧是一个表达式,会在输入装配阶段被求值。
node calcPrice : CalcPriceOperator {
input {
user = fetchUser.output // whole output object
products = fetchProducts.output // whole output object
userId = fetchUser.output.userId // nested field
tax = ctx.taxRate // context value
label = "order" // literal string
}
}
三个来源,同一个 block:
| 来源 | 语法 | 例子 |
|---|---|---|
| Context | ctx.fieldName | ctx.taxRate |
| 上游输出 | nodeName.output 或 nodeName.output.field | fetchUser.output.userId |
| 字面量 | 字符串或数字字面量 | "order"、42 |