起始
标签平台作为数据平台建设的一部分,尤其是在互联网电商平台中,有着重要的作用。本人在公司接手并且重构了整个标签平台的核心逻辑。对标签平台有一定的了解。写这篇文章的契机是几个数仓的哥们,问到了这方面的问题,正好我也可以总结一下。
本文从技术角度,通过以下几个方面来阐述标签平台的建设历程
- 什么是特征/标签
- 什么是标签平台
- 标签平台可以解决的问题
- 标签平台迭代历程
- 标签平台核心功能的解析
- 离线特征平台
- 实时特征平台
- 标签组装和调度
- 标签分析
- 查询引擎
- 数据流的走向 - 总结
关键字解读
特征:对某个维度特征的描述,特征也是标签,只不过是原子维度的标签。
标签:一组特征的组合。
实验: 一组相似或者完全不同的标签的组合,主要做某种优化的尝试。
正文
什么是特征/标签
特征就是对某个维度的描述,比如人,有各种固定的属性(年轻,身高,体重),行为的维度(一天挣多少钱,喜欢什么颜色)这些也可以归结为特征。而标签更好理解,标签就是一组特征的组合。从广义上来讲标签和特征是一类东西。叫法不一样而已。
特征大致分为三类:
统计型特征
一些基础的属性比如年龄,城市星座,和一些通过统计数据中得到的(活跃时常,活跃天数等)。这些基础属性和统计类属性构成了特征的基础
规则型特征
通过一些规则产生。一般是对一些统计型标签估计量化形成业务可以看懂的特征。这类特征在业务上比较重要,因为一般使用平台的都是运营的同学,这些已知规则的标签,业务的同学才能看得懂。比如针对商品的一些标,双11大促标,7天无理由退货标等等。
机器学习挖掘型
通过机器学习挖掘产生,比如判断用户性别,用户购买偏好,流失意向,一般开发成本比较高,占比较小。
特征是标签平台的基础,一般而言,特征越丰富,圈选的标签就越丰富,所以有时候就会有一个误区,数仓同学在开发特征的时候,直接就是把业务的各种大宽表导入进来。从业务上看大而全,但是实际应用中很多特征一次都没有用过。在我们的一些经验里面,应该把基础特征做全,其他根据业务的需求增量去开发,避免一些无用特征的浪费,而且还要根据特征的使用情况,淘汰掉一些使用度很低的特征。
特征/标签的口径说明应该是特征/标签体系中最重要的部分,特征的口径/说明决定了特征的使用度。从系统开发的角度,一方面是尽量提供明确的口径说明,血缘关系,特征的联系人,从应用的角度。尽量多创建一些通用的规则型特征,方便业务方使用。
什么是标签平台
在狭义的理解中,标签平台就是做标签圈选的。以某电商标签平台为例,可以给用户打标签(年龄,职业,收入…),也可以给商品打标签(颜色,尺寸,类型…),当然也可以给商家打标签(星级, 排名)。
但是特征从哪里来?标签怎么组装?标签怎么存储?如何进行标签分析?数据如何回流?这些都是在标签平台的范畴之内。先整理了一个标签从特征生产,特征组装成标签, 查询引擎一整个流程。给大家一个直面的认识。如下图:
标签平台包含特征,标签,查询三个大块,这几大块组合起来就是一个标签平台。但是从狭义上来讲,特征平台又是单独的,查询引擎可以归属到数据平台统一数据服务中。所以标签平台其实是多个系统的整合。
标签平台可以解决的问题
我这边只从互联网电商平台的角度说一下应用的场景
- 站内动态投放(页面按钮,弹窗,红包等个性化投放)。
- 站外投放广告(根据设备号在其他平台投放广告,进行ROI/效果分析)。
- 推送(站内信/手机号推送信息)。
- 个性化搜索/推荐/相关商品推荐。
- A/B实验,以达到优化app使用体验,达到用户增长的目的。
- 用户画像,商品画像,风控用户画像等等。
在这几类中应用最多的是推送,投放场景。其实风控,商品其实是很好的切入点(风控的人群定位,自定义搜索相关性商品)。有很多的应用场景。我们的标签平台最初是基于用户来做的,毕竟数据量庞大,在投放,推送中有重要的地位。
在几种应用场景中,都要根据业务进行定制化的开发,比如说投放场景,我们开发了kv存储和标签平台进行绑定。这些其实都已经跨业务域了。但是从另外一个角度上来说,平台只有和业务结合,才能更好的服务于业务。
标签平台迭代历程
1.0版本
- 只支持离线标签,使用自定义sql,一个标签一个sql脚本,存储到kv,hive中。给下游提供接口服务。
2.0版本
- sql映射前端字段,每个业务域都有自己的宽表体系。但是当遇到二级筛选维度的时候就比较麻烦,是把二级维度组装成一级维度,还是通过系统配置的形成做到前端二次筛选。当然我们选择了第二条难走的路。运营同学可以很方便的选择特征组装标签,然后通过presto进行预测数量级。
- 实时数据被整合进来,通过规则引擎接入kafka数据,然后写入到kv。
3.0版本
- 特征平台的引入,我们通过特征平台把各种业务宽表组装成一张hive宽表,最终导入到es引擎中。
- 实时数仓的分层,数据分发到不同的存储引擎单独维护。
在1.0版本中我们遇到了因为业务量疯狂增长,sql脚本增长太快,而且复用度很低的情况。而且运营同学一般不会sql,开发周期拉长。
在2.0版本中运营同学可以方便的通过映射组装sql。但是底层映射其实包含了大量元数据的映射。数仓同学做了很多大宽表,但是很多字段都是闲置状态,大部分都浪费了。
在3.0版本中,我们引入了特征平台,把离线特征下沉到es,实时特征下沉到kv。这样把特征从标签平台一整套中剥离出单独的应用。方便了系统的管理。在2.0版本中做特征,标签分析,需要依赖spark。不能做到秒级别返回。用户体验很差。但是在3.0版本中es对于亿级别数据各种聚合类查询,能达到毫秒级返回。完全能够满足我们日常的使用需求。
实时特征在flinksql的普及之下, 业务的同学不同纠结于做各种正则解析,口径对比了。只负责拿到kafka对应的字段,然后批量插入到kv就行,其他交给数仓的同学。并且我们针对实时的分析场景引入了tidb(后面tidb下线,后续迁移到clickhouse)。
标签平台核心功能的解析
标签平台是一个融合的系统,包含了离线特征平台,实时特征平台,标签调度平台,标签组装与分析平台,查询引擎几部分组成,具体如图
- 最低层的数据源包含了hive,中间表存储放到hbase中,实时数据通过消息报获取。
- 特征平台包含离线特征和实现特征两部分。离线特征通过spark+hbase计算,实时特征通过flinksql计算。
- 特征存储分三块,ES存储离线特征的全量数据。MYSQL存储特征的元数据,kv存储实时特征的全量数据。
- 标签平台分为标签圈选和标签分析两部分。
- 标签分为三类,离线标签,混合标签,实时标签。混合标签是离线特征和混合特征一起使用,是一种实时的折中方案。
- 查询引擎 包括标签解析,特征值匹配,具体匹配看下文。
离线特征平台
- 离线特征平台 主要做离线特征的口径,与离线特征生成。 一般通过配置化的形式,把聚合,过滤包装成组件,整合成spark脚本,发送到调度系统执行。
- 在我们的场景下,特征存储到es,中间表使用hbase,使用hbase的原因是宽表的join在hive里面其实是有点困难的,我们这边使用了一个取巧的方式hbase的buckload, 按天生成新的特征表hbase,每天去更新es。这样效率会很高。
一般来说,es数据一般是全量,这个全量可以使用全量join增量数据得到。
这种场景下es有自己的缺陷,无法使用历史的数据。所以有历史需求的,可以考虑自定义sql。
实时特征平台
实时特征主要依赖flink实时数仓来实现,实时数仓负责进行ETL和口径的梳理,平台只负责批量导入到kv即可。
在最终存储这块,我们做了多数据源存储的方式,在最初的模型里面,我们使用kv,tidb,hbase三种存储。做了存储,分析,高可用。
实时特征导入到kv会有历史数据的追溯的问题,这个在以往的经验,找个相同口径离线sql然后导入到kv。这个是要和实时特征一块维护起来的。万一kv挂了之后可以通过任务来找回历史(当然你可以存储到hbase里面,不过高并发的场景不一定适合。)。
标签组装和调度
标签的组装,主要是标签的关系,特征的拼装。特征的类型和前端展示。下面列出的是字段类型和页面的显示类型。
字段类型 | 前端展示类型 |
boolean | 等于/不等于 |
字符串枚举 | 包含/不包含 |
字符串 | 手工输入 |
数字枚举 | 包含/不包含 |
数字 | 手工输入 |
数字偏好类 | 多输入框 |
日期 | 普通日期/动态日期 |
特征的关系,这个可以参考下神策的做法,我个人觉得神策的平台页面做的不错。我们的系统其实和神策的类似,不过可操作性确实没有神策好。扯远了。标签的关系,其实就是且或非。且或可以自己实现一套解析和反解析的逻辑。非的逻辑其实挺有意思的。有些需要在特征的时候就要做非。有些可以通过运算符来做。比如实时的特征(ag: 是否是平台的vip会员,一般在kv里面只存储一种特征值,我们在筛选非平台会员的时候就是这种场景)(下图参考了神策)
标签的调度 这个主要是涉及到标签状态机的转换。具体的状态根据业务的不同也有所不同。
标签平台的调度在最初的时候是自己开发了一个小小的应用级调度。其实可以融入到数据平台的DAG调度中,标签平台只负责标签元数据管理和状态机的转变。
标签分析
标签分析是标签平台的核心功能。标签分析包括特征的分析,标签特征分析,标签差异度。标签模型实验分析。
- 特征分析 包括特征占比与分布,特征平均数,中间数,极值,以及特征随机值占比等。
- 标签特征分析 包括特征在指定N个特征的表现和分布,以及多个标签在相同特征的分析对比。
- 标签差异度 多个标签在一组特征中选出差异性最大的N个特征。
- 标签模型实验分析 把标签的数据在一些分析模型上进行数据分析(留存、复购扥等)
在标签分析中一般分为事前,事中,事后三个阶段:
- 事前 选择合适的特征,根据特征的数据分析,精确匹配目标标签。
- 事中 圈选标签过程中,可以直接套用离线的模型进行实时的分析。
- 事后 标签数据产出之后,数据回流到hive,通过其他的数据分析模型进行迭代优化。
在整个分析的场景中,数据回流和分析模型的沉淀是两个比较重要的点。一般而言,1:分析的场景一般在离线场景比较多。一般以spark作为分析的引擎,有时候需要添加一些算法进去。所以数据一般需要从es或者其他数据源导入到hive中进行分析。2:分析的模型一般都比较固定,但是需要结合前端页面的展示才能方便用户进行分析,各种图的对比展示才能一目了然标签的差异。
标签分析需要跨部门合作。标签的效果数据通过业务部门得到。然后再通过标签分析的模型进行效果分析。这是一个偏应用的场景。标签分析模型和分析数据回流的模型,是标签分析最重要的。
查询引擎
查询引擎在数据平台中,其实应该算是统一数据服务层的逻辑,不过因为查询引擎涉及具体的逻辑计算,所以单独拎出来。在我们的场景下,一般只用kv做存储。所以并发量是很可观的。而现在kv又做了主备。其实并不用太关心kv挂掉的情况,如果你实在担心,只能再多存储一份到hbase了。其实也是可以的。
表达式匹配的话,我用的是googlecode aviator来做的。相对旧版本匹配效率提升了不少。不过这里面有个坑,在这就不展开说了。
在整个离线/实时数据存储上,hdfs,kv是两个相对重要的存储。kv存储引擎的数据结构如下:
- 离线标签都是N+1的数据,批量生成,存储的都是离线标签数组,在查询的时候直接根据用户查询匹配即可。
- 实时标签就需要把实时的特征值和表达式关联起来,才能组成一个实时的标签。一般我们的做法都是根据业务把所有实时标签拉取出来,实时迭代匹配。
- 混合标签,包含了离线特征和实时特征,这种场景相对少一点。比如sex这个特征,如果做成实时的也是可以的,但是一般都是做成离线的,如果和实时特征进行匹配就需要做成混合标签。这个具体怎么搞,看上面的数据图即可。
数据流的走向
离线特征一般存储在hive,经过hbase中转导入到es作为查询服务,实时特征一般经过kafka存储到kv。在整个标签组装存储过程中,数据流转到hdfs和kv,并且把标签的数据回流到hive。并且最终通过查询服务暴露给第三方业务系统。第三方业务系统把使用后的数据和效果反馈给离线数仓和标签的数据结合起来进行进一步的数据效果分析。
这是一整套数据的链路。最重要的一点就是数据的回流。数据只有流转起来标签平台的价值才会体现出来。
在整个平台的建设中,我们发现数据的流转和回流是最困难的。数据来源很多(外部数据,业务系统数据,其他等),整合到一起,并且沉淀到分析模型中,形成数据流转。所以我们在整合整个系统架构,以及在存储的选择上,都是根据这些已有的业务场景选择一个折中的方案。这个需要和业务有着很深的联系。
结尾
整个标签平台的逻辑大致就是这样。我们的系统是在业务规模不断扩大,以及场景的不断丰富而迭代出来,不是一蹴而就,我是以一个开发的角度去看整个架构的,其实会缺少很多东西。但是似乎好像缺少了点什么东西。对的,偏分析的场景,这个到底算不算标签平台的一部分,其实是值得思考的。如果是两个分开的平台,其实会有一些割裂。比如外投的一些效果,怎么回流到标签平台做分析,推送的数据,用户的效果分析,以及如何进一步的优化标签的圈选效果。这些是值得思考的。
在整个标签平台的建设中其实更应该站在用户的角度上去思考问题,我们遇到了一些问题,这个可以给大家分享一下:
- 特征的口径问题,一般我们是通过描述,离线表,实时消息报,接口人去解决。其实这些都已经满足了。但是通过业务方的反馈,其实业务方还是挺难理解一些口径。比如gmv这个指标。哈哈。所以要规划好特征的多级分类。并且做好数据平台的异构数据源的血缘链路,这样就更好追溯了,所见即所得嘛。
- 实时特征分析场景,在最初的时候我们实时数据只是存储到kv,但是在实际圈选场景中需要看到目标的数量,以及根据分析场景,kv就不太满足了,所以我们后来选择双写或者三写,一方面为了稳定性,另一方面可以做更多的分析场景,我们选择了tidb,在亿级数据量几十个特征的前提先,我创建N个索引,其实还是能满足需求的,现在公司在搭建clickhouse,不知道有没有更好的表现。
- 用户标签 很多人把标签平台和用户标签等价。其实是有误区的,最初的时候我们在做标签平台,其实只是做了用户,像商品,商家等,其实都是没有做的。更可惜的是在大部分场景下,用户和商品,商家等其实是割裂的。其实如何能关联好这几类挺重要的,比如淘宝的推荐系统,用户自定义搜索根据偏好进行推荐(包含了广告商品,用户偏好类商品,热度商品等等),标签平台并不是各自为政,而是把业务和目标特征关联起来。形成数据流的闭环,这个是最难的,也是必须要做的。
- 自动化的特征生成 无论是离线特征还是实时特征,特征的开发能够自动化运维,增加删除特征,特征历史数据的写入等标签的诉求和标签的维护,全部由数仓同学负责,数据平台的同学只负责整体系统的维护。
- 降低无效标签/特征的堆积 最初我们是通过标签的有效期来控制,最大一周的有效期,长期标签通过管理员去维护,因为数仓同学负责整个公共标签的维护,所以能很大程度避免标签的重复创建,通过标签的使用频次和下游的调用,来删除无效的特征。
- 数据的回流,这个在结尾的时候不得不提,而且这个也是最难的。比如外投,如果把不同平台外投的数据整合起来,分析外投的效果,然后优化标签的圈选。类似的例子很多,标签平台和其他平台数据的整合,数据回流,这样才能更好的沉淀标签和数据。但是在实际的场景下,每个业务方各自为政。数据是没有流通的。经验只在bi那边有部分沉淀,完全没有落到系统上面去。这个其实也是一种悲哀谁能整合这些,谁就能走的更远,哈哈,说多了,不过在这种场景下还做过一些有意思的东西,我们在分析一些推送场景的时候,发现业务方大批量进行app内部推送,导致很多用户直接关闭了消息提醒,很多无效的推送,在这种场景下我们增加了是否关闭推送提醒的特征,推送数据大大降低,其实这也是一种精细化推送。