跳转至

特征服务设计总结

整理自 spider_scf_featurerouting + neirong_scf_appmainrecom 代码梳理,及大厂 Feature Store / 在线特征实践阅读笔记。
更新:2026-05-19


目录

  1. 特征参数设计:两种方案对比
  2. 本司架构:featurerouting 特征路由服务
  3. appmainrecom 侧特征加载
  4. 数据源要求与前缀约定
  5. 跨城兴趣分(WList)接入分析
  6. 大厂常见架构模式
  7. 推荐阅读文章

1. 特征参数设计:两种方案对比

场景:司机近 7 天有效行程记录,如何定义「参数」与「特征」?

对比维度 方案 1:参数=司机,特征=近7天有效行程 方案 2:参数=司机+7天+有效,特征=行程记录
设计定位 标准特征服务。高并发、低延迟 KV 读取 在线数据服务 / 轻量计算引擎。带过滤、聚合逻辑
读性能 极高(<5ms)。Redis/HBase 预计算值一次读出 较低且不稳定。服务内过滤聚合,随数据量劣化
高并发 QPS 极高。推荐/派单核心链路可支撑百万级 QPS 较低。动态参数导致缓存命中率低
模型对接 友好。Schema 固定、特征列表确定 较差。特征长度/口径动态变化
维护成本 。离线/实时算好写入,在线服务当「哑管道」 。特征服务内堆业务逻辑

大厂常用思路:在线侧尽量 方案 1——参数是实体 ID(user/item),时间窗口、过滤条件在 离线/近线生产 时固化进特征名或存储 key;动态维度(如「当前出发城」)要么在 调用方拼 key,要么走 LocalLoad / 算子 而非塞进特征服务 RPC 参数。


2. 本司架构:featurerouting 特征路由服务

2.1 项目定位

Maven 双模块 SCF 服务:按 featureId 路由到不同存储/画像服务,批量拉取特征字符串。

spider_scf_featurerouting/
├── contract/     # IFeatureRoutingService、FeatureResult、GroupBatchRequest
└── service/      # Router、FeatureSource、字典、底层 IO 工具

2.2 两类「加载」

类型 时机 数据源 作用
元数据加载 启动 + 每 5 分钟 MySQL featureId → sourceId、查询字段、压缩方式
特征值加载 每次 RPC WTable / WList / Redis / 画像 SCF 按 id 批量取特征值

元数据表:

  • t_feature_datasourcesource_id, source_type, source_config(JSON)
  • t_feature_configfeature_id, source_id, feature_config(JSON)

2.3 RPC 入口与调用链

方法 说明
getFeature 单 id,内部转 getFeatureBatch
getFeatureBatch Router:按数据源分组并行读
getFeatureBatchGroup GroupParallelRouter:多组并行,组内同 Router
SCF Client
  → FeatureRoutingService
  → Router.route(featureIds)          # featureId → sourceId(FeatureConfigDict)
  → 并行 FeatureReader × N
  → FeatureSourceFactory.createFeatureSource(sourceId)
  → IFeatureSource.getFeaturesBatch(ids, featureIds)
  → 合并 ConcurrentHashMap<id, Map<featureId, value>>

超时:Router 45s,GroupParallelRouter 46s

2.4 四种 FeatureSource(source_type)

type_id 枚举 实现类 底层 IO
1 WLIST WListFeatureSource WlistClient.scan
2 WTABLE WTableFeatureSource WtableClient.mGet
3 REDIS_CLUSTER RedisClusterFeatureSource Redisson readAllMapAsync
4 FACETAGADSVC FaceTagADSvcFeatureSource 画像 SCF / OneService

统一接口:IFeatureSource.getFeaturesBatch(ids, featureIds) → 返回与 ids 等长的 List<Map<featureId, value>>

2.5 各源读法要点

Redis

  • id = Hash 的 完整 key(原样,不自动加前缀)
  • 一次 readAllMap 拉整表,再按 feature_config.field 取子字段
  • 唯一启用 Guava 本地缓存的数据源(isUseCache=true

WTable

  • rowKey = idcolKey = feature_config.field
  • 支持 Gzip / Snappy 解压(compressId
  • 注入 cache 但 未使用

WList

  • id = scan 的 list key
  • 单 feature 只输出 一个字段 的多行值,用 | 拼接
  • 配置:field, filter, isAsc, limit, fieldType

画像

  • id 当作 imei;personasType:1=FaceTagADSvc,2=RealtimeFaceSvc,≥100=OneService
  • personasType=1 时服务内部会拼 wimei 前缀

2.6 部署配置(featurerouting)

路径:service/deploy/featurerouting/config/

文件 用途
config.properties MySQL(featuredb_*)
wtable_{clientId}.properties WTable 集群
wlist_{clientId}.properties WList 集群
{clientId}.json Redisson Redis 集群

注意:无 prefix 配置项;featurerouting 不会对 id 做任何前缀/后缀处理


3. appmainrecom 侧特征加载

3.1 与 featurerouting 的关系

  • 依赖:featurerouting.contract
  • 封装:FeatureRoutingService.getFeatureBatchGroupIFeatureRoutingService.PROXY

3.2 用户特征两条路径(并行)

路径 register_type 加载类 说明
TRIBE_FEATURE 0 BaseUserFeatureLoad 调 featurerouting RPC
LOCAL_FILL 本地填充 LocalUserFeatureLoad map_funcLocalLoadFactory → 各 *Load 实现

物品特征:ItemFeatureLoadkey_type=9(物品 nid),同样走 featurerouting 分组批量。

3.3 配置表

项目 作用
t_feature_register appmainrecom feature_id, key_type, key_prefix, key_suffix, map_func, register_config
t_feature_config featurerouting 查询语义(field、filter、compress 等)
t_feature_datasource featurerouting 连接与 source_type

feature_id 两边必须一致

3.4 Key 拼装规则(调用方)

用户特征:

传给 featurerouting 的 id = key_prefix + key + key_suffix
key 来自 key_type:1=uid, 2=did, 3=uniqueID

物品特征:

id = prefix + nid + suffix
或 dyprefix=entitytype1_ → {entityType}_ + prefix + nid + suffix

取回后按 group 元数据 剥掉 prefix/suffix 还原 nid。

特殊:suffix=vector 时用桶号作 Redis key,非 nid。


4. 数据源要求与前缀约定

4.1 能否有前缀?

问题 结论
Redis/WList/WTable 能有前缀吗? 可以,前缀是 key 的一部分
featurerouting 会自动加前缀吗? 不会
前缀在哪配? appmainrecom t_feature_register.key_prefix / key_suffix
存储侧要求? 写入 key 必须等于 调用时传入的完整 id
画像能用 prefix 吗? 一般 不要;type=1 内部已有 wimei 逻辑

4.2 新特征接入检查清单

  1. 确定存储类型(Redis Hash / WTable / WList / 画像)
  2. 确定 完整 key(含前缀)在存储中的实际形态
  3. featurerouting:注册 t_feature_datasource + t_feature_config,部署对应 properties/json
  4. appmainrecom:注册 t_feature_registerkey_prefix/suffix 与存储一致
  5. map_func 将 RPC 返回的 string 转为目标 FeatureItem 类型
  6. 拼好的完整 idgetFeatureBatch 验证

5. 跨城兴趣分(WList)接入分析

5.1 现状(已实现,走 LocalLoad)

CrossCityFeatureFromWListLoad
注册 register_type=LOCAL_FILL, map_func=CrossCityFeatureFromWListLoad
WList index=10 → wlist10.properties, bid=1378287663
兴趣分 tableId=1, key=imei + "_" + departCityId
强度 tableId=2, key=imei
register_id 600100(map_list), 600101(double)

逻辑:多字段 scan → 去重 → 排除出发城 → 按分数排序 → 组装 List<Map<String, FeatureItem>>

下游:RecomPrepare / CrossCityExpParam.fillSortedCityScoreListFromInterestFeature

5.2 若走统一 featurerouting 的卡点

卡点 说明 严重度
动态 key imei_出发城BaseUserFeatureLoad 仅支持静态 prefix/suffix ★★★
返回结构 featurerouting WList 只返回单字段 \| 拼接 string,非 map_list ★★★
业务逻辑 去重、过滤、排序在 WList 源中不存在 ★★
双表双 key 需两个 source_id(tableId 在数据源级)
部署分裂 featurerouting 需新增 wlist_1378287663.properties,当前无 wlist10
WList 缓存 FeatureSource 注入 cache 但未使用

5.3 推荐路线

方案 说明
A. 维持 LocalLoad 零改造,已上线;与 featurerouting 并行共存
B. 半统一 LocalLoad 内调 featurerouting,本地仍拼 key + 解析 map_list
C. 真统一 BaseUserFeatureLoad 支持动态后缀 + 扩展 WListFeatureSource 多字段/JSON + 新 FeatureMap

6. 大厂常见架构模式

flowchart TB
    subgraph offline [离线/近线]
        A[日志/行为] --> B[Spark/Flink 特征生产]
        B --> C[Hive/离线表]
        C --> D[同步 KV/Redis/WTable/WList]
    end
    subgraph online [在线推理]
        E[推荐服务] --> F[特征加载层]
        F --> G{路由/注册表}
        G --> H[KV 批量读]
        G --> I[画像 RPC]
        G --> J[本地算子 LocalLoad]
        F --> K[特征拼接 / 算子图]
        K --> L[模型 / 规则]
    end
    D --> H
模式 大厂做法 本司对应
三层分离 离线生产 / 近线同步 / 在线只读 featurerouting = 在线读+路由
Feature Store 特征注册、元数据、按 ID 批量拉取 MySQL + t_feature_register
多存储路由 按 featureId 路由 FeatureSourceType 四类
Key 约定 调用方或平台拼复合 key key_prefix/suffix;跨城 LocalLoad
特征算子 FeatureOperator、配置化 DAG LocalLoad + map_func
训练/在线一致 同一 feature 定义 feature_id 对齐

7. 推荐阅读文章

7.1 国内大厂(优先)

网页版(MkDocs)不会把裸 https://... 自动变成可点链接,须写成 [标题](url)。Obsidian 里裸 URL 能点,属编辑器行为差异。

文章 重点
美团外卖排序特征生产框架(2016) KV 推送 + FeatureOperator 算子
美团在线特征数据存取(2017) 低延迟、压缩、分层存储
美团在线特征生产调度(2017) 近线调度与同步
美团外卖特征平台(2021) 语义合并、多任务调度
腾讯新闻推荐架构升级 配置化特征算子、图优化
网易新闻特征算子篇 算子抽象、图剪枝
阿里 PAI FeatureStore 推荐实践 离在线一体
FeatHub 流批一体特征平台 Flink、Point-in-time
蚂蚁 Flink 实时特征平台 Skyline、高性能 Serving

7.2 国际大厂

文章 重点
Uber Palette Metastore 特征元数据与 Serving
Uber Michelangelo 概览 ML 平台全貌
LinkedIn 开源 Feathr 按名取特征、训练在线一致
Vertex AI Feature Store 托管 Feature Store
在线 Serve 特征值 Feature View 在线读
Netflix Metaflow 与 ML 系统 数据层特征工程

7.3 开源 Feature Store

资源
What is a Feature Store (Feast)
Feast 推理架构
Feast 在线性能调优
Tecton 在线 Serving FAQ

7.4 建议阅读顺序

  1. 美团 2016 特征生产框架 → 建立「生产→KV→在线加载」直觉
  2. 美团 2021 特征平台 → 平台化与语义合并
  3. Uber Palette → 元数据 + Serving
  4. Feast 概念文 → 通用术语
  5. 腾讯新闻架构 → 在线算子工程化

附录:关键代码路径

模块 路径
featurerouting 入口 spider_scf_featurerouting/.../FeatureRoutingService.java
路由 .../Router.java, GroupParallelRouter.java
工厂 .../FeatureSourceFactory.java
WList 源 .../WListFeatureSource.java
app 用户特征 RPC neirong_scf_appmainrecom/.../BaseUserFeatureLoad.java
app 物品特征 RPC .../ItemFeatureLoad.java
跨城 LocalLoad .../CrossCityFeatureFromWListLoad.java
特征注册实体 .../FeatureRegisterBean.java

本文档为收件箱草稿,后续可归档至「推荐系统 / 特征工程」专题目录并补充具体 feature_id 配置样例。