特征注册核心概念:特征ID、特征名称、特征类型、特征维度、特征版本
好,咱们正式开始聊特征注册。上一章我大概提了一下特征注册在整个特征平台里的位置,这一章咱们把最核心的几个概念掰开揉碎讲清楚。
你想想看,一个特征平台里可能管理着成千上万个特征。如果没有一套清晰的标识和分类体系,那基本就是灾难。我在项目中就见过,同一个特征在不同团队叫法不一样,最后上线模型的时候才发现特征冲突——嗯,那场面挺尴尬的。
特征ID:特征的唯一身份证
特征ID,说白了就是每个特征的全局唯一标识。我习惯用64位整数或者UUID来生成。为什么不用字符串?因为整数做索引和哈希的效率高得多,尤其在实时特征计算场景下。
核心原则:特征ID一旦分配,终身不变。哪怕特征下线了,ID也不能复用。
我曾经踩过一个坑:早期设计时觉得特征ID用自增主键就行,结果后来做特征回溯和版本对比时,发现ID被重新分配给了新特征,历史数据全乱了。从那以后,我强制要求所有特征ID必须用雪花算法或者UUID生成,绝不依赖数据库自增。
特征ID的生成策略,我建议这样选:
- 雪花算法:适合分布式场景,64位长整型,按时间戳+机器ID+序列号生成,性能高、不重复
- UUID:适合小规模团队,128位字符串,生成简单,但存储和索引效率低
- 业务前缀+自增:适合特征数量少的场景,比如"feat_0001",但扩展性差
我个人更倾向雪花算法。你想想看,在微服务架构下,多个服务同时注册特征,自增ID很容易冲突。雪花算法天然支持分布式,而且还能从ID里反推出注册时间,排查问题的时候特别有用。
特征名称:让人看懂的名字
特征ID是给机器看的,特征名称是给人看的。一个好的特征名称,应该让人一眼就知道这个特征是什么、从哪里来。
我见过最离谱的特征名称叫"f_123",代码里全是这种名字,三个月后连写代码的人自己都忘了是什么意思。所以,命名规范一定要定死。
我推荐这种命名风格:
# 推荐格式:{数据源}_{实体类型}_{业务含义}_{聚合方式}
user_30d_avg_order_amount
item_7d_click_count
device_1d_active_flag
# 不推荐格式
f_123
aaa_bbb
test_feature_v2_final
这里有个小技巧:特征名称里不要带版本号。版本号是单独管理的,写在名称里会让后续的版本管理变得非常痛苦。我曾经接手过一个项目,特征名称叫"user_age_v3_final_final",你猜后来有没有v4?
命名规范建议:
- 全小写,用下划线分隔
- 长度不超过64个字符
- 禁止使用特殊字符(除了下划线)
- 禁止以数字开头
- 禁止包含版本号、日期等可变信息
特征类型:连续、离散、ID类
特征类型决定了这个特征怎么存储、怎么计算、怎么参与模型训练。我一般把特征类型分成三大类:
| 类型 | 说明 | 示例 | 存储建议 |
|---|---|---|---|
| 连续型 | 数值范围连续,可比较大小 | 年龄、收入、点击率 | Float/Double |
| 离散型 | 有限个取值,无序 | 性别、城市、设备类型 | String/Enum |
| ID类 | 标识性ID,取值空间大 | 用户ID、商品ID、设备ID | String/Long |
你可能会问,为什么要把ID类单独拎出来?
嗯,这里有个坑。ID类特征虽然看起来像数值,但它不能直接参与数值计算。比如用户ID是1001和1002,你不能说1002比1001大。ID类特征通常要做embedding或者one-hot编码,存储和计算方式跟连续型完全不一样。
我记得有一次,新来的同事把一个用户ID特征标成了连续型,结果模型训练时直接拿ID当数值算,模型效果一塌糊涂。排查了半天才发现是类型标错了。
类型选择避坑指南:
- 不要把所有数值都标成连续型——比如邮编虽然是数字,但本质是离散的
- ID类特征不要参与数值运算——它只做匹配和映射
- 离散型特征取值超过1000个时,建议考虑转为ID类做embedding
特征维度:特征的空间归属
特征维度,说白了就是这个特征属于谁。是用户的特征?还是商品的特征?还是某个时间窗口的特征?
我习惯把维度分成三层:
- 实体维度:特征属于哪个实体,比如用户、商品、设备
- 时间维度:特征的时间窗口,比如近7天、近30天、实时
- 场景维度:特征在哪个场景下使用,比如推荐、搜索、广告
维度设计得好,特征复用率会大幅提升。我见过一个团队,同样的"用户近7天购买金额"特征,在推荐场景和搜索场景各注册了一次,维度字段一个写"推荐",一个写"搜索"。其实特征计算逻辑完全一样,只是使用场景不同。
我的建议是:维度只描述特征本身的属性,不描述使用场景。使用场景应该通过特征权限和标签来管理,而不是写在维度里。
特征版本:让特征可追溯
特征版本可能是最容易被忽视的概念。很多人觉得特征定义好了就不会变,但现实是——特征的计算逻辑、数据源、聚合方式都可能需要调整。
我经历过最惨的一次:线上模型用的特征,计算逻辑被悄悄改了,没有走版本管理。结果模型效果突然下降,排查了三天才发现是特征变了。从那以后,我强制要求所有特征必须有版本号,每次变更必须生成新版本。
版本管理我建议这样设计:
# 版本号格式:主版本.次版本.修订号
# 主版本:特征计算逻辑或数据源变更
# 次版本:特征参数或配置调整
# 修订号:bug修复或性能优化
# 示例
user_30d_avg_order_amount v1.0.0 # 初始版本
user_30d_avg_order_amount v2.0.0 # 数据源从A表切到B表
user_30d_avg_order_amount v2.1.0 # 增加了异常值过滤
user_30d_avg_order_amount v2.1.1 # 修复了空值处理bug
版本管理核心原则:
- 版本一旦发布,不可修改
- 新版本必须保留旧版本的历史数据
- 线上模型必须指定使用哪个版本
- 版本回滚要支持一键操作
你想想看,如果没有版本管理,你怎么知道线上模型用的是哪个版本的特征?出了问题怎么回滚?
核心概念关系图
下面这张图把五个核心概念的关系梳理了一下,你可以对照着理解:
实际注册时的元数据模板
最后,我分享一下在实际项目中用的特征注册元数据模板。每次注册新特征,都按这个模板填写,基本不会漏东西:
{
"feature_id": 100001,
"feature_name": "user_30d_avg_order_amount",
"feature_type": "continuous",
"dimension": {
"entity": "user",
"time_window": "30d",
"aggregation": "avg"
},
"version": "1.0.0",
"description": "用户近30天平均订单金额",
"data_source": "dwd_order_di",
"owner": "recommend_team",
"status": "online"
}
这个模板看起来简单,但每个字段背后都有讲究。比如feature_type填"continuous"还是"float",我建议统一用枚举值,避免不同团队写的不一样。再比如dimension里的time_window,一定要标准化成"7d"、"30d"这种格式,不要出现"7天"、"近一周"这种五花八门的写法。
嗯,这一章的内容就到这里。五个核心概念——特征ID、特征名称、特征类型、特征维度、特征版本——是特征注册的基石。你把这些搞清楚了,后面的注册流程、版本管理、元数据治理就都好办了。