这两种模式都用于处理原始特征数据(raw feature),区别在于特征生成(Feature Generate)的执行方式。
FG_NORMAL — Python 逐特征处理
- 定义:data.proto 中描述为 "we use python to run feature generate"
- 初始化时机:每个 feature 对象在创建时调用 init_fg(),各自独立创建一个 pyfg.FgArrowHandler 实例
- 处理方式:在 _parse_feature_normal 中,逐个特征调用 feature.parse(input_data) 进行 Python 层面的特征解析
- 输入名获取:通过遍历每个 feature 的 feature.inputs 属性获取所需的输入字段名
- 限制:不支持 stub_type(虚拟特征,中间特征)
FG_DAG — C++ DAG 引擎批量处理
- 定义:data.proto 中描述为 "we use fg_handler to run feature generate"
- 初始化时机:DataParser 构造时创建一个全局的 pyfg.FgArrowHandler(_init_fg_hander),它会根据所有特征的 fg_json 构建一个 DAG 计算图
- 处理方式:在 _parse_feature_fg_handler 中,一次性调用 self._fg_handler.process_arrow(input_data_fg) 把所有原始输入丢给 C++ 引擎,批量完成所有特征的生成
- 输入名获取:通过 fg_handler 的 user_inputs() / item_inputs() / context_inputs() API 获取,自动识别 user/item/context 侧
- 支持:stub_type(虚拟特征,中间特征)、特征间依赖(DAG 拓扑排序)、自动识别 is_user_feat
对比总结
| 维度 | FG_NORMAL | FG_DAG |
| 执行引擎 | Python 逐特征循环 | C++ DAG 引擎一次性处理 |
| FG Handler 数量 | 每个特征一个 | 全局一个(共享) |
| 性能 | 较慢(Python 循环开销) | 更快(C++ 并行 + 批处理) |
| 特征间依赖 | 不支持(独立处理) | 支持(DAG 拓扑排序),就是特征之间可以前后依赖 |
| stub_type | 不支持 | 支持 |
| user/item 自动识别 | 需通过 expression 的 side 推断 |
fg_handler 自动提供 user_inputs() 等 |
| INPUT_TILE 支持 | 支持 | 支持 |
什么时候用哪个?
推荐使用 FG_DAG(大多数场景):
- 生产环境训练/推理 — 性能更好
- 特征之间存在依赖关系(如一个特征的输出是另一个特征的输入)
- 需要使用 stub_type 虚拟特征
- 配置了 fg_threads > 0 时自动选用
使用 FG_NORMAL:
- 简单场景 / 调试阶段,不需要 C++ DAG 引擎
- 特征配置简单、无特征间依赖
- 未设置 fg_threads(即 fg_threads = 0)时的默认行为
从 config_util.py 的兼容逻辑可以看出:旧配置中 fg_threads > 0 就对应 FG_DAG,否则对应 FGNORMAL。新配置直接通过 data_config.fg_mode 显式指定