用户画像实践:神策标签生产引擎架构
点击上方“数据管道”,选择“置顶星标”公众号
干货福利,第一时间送达
分享嘉宾:王琛@神策数据
编辑整理:冯露
出品平台:DataFunTalk
用户标签及其应用场景
标签生产平台的需求
批流一体的标签生产架构
总结
1. 什么是用户标签
简单说,就是对用户的某个维度特征的描述。对一群用户而言,我们为了能让业务做的更好,就想知道他们的很多特征。比如说,我现在有个10万块钱的活动预算,那这个钱应该集中花在哪里呢?针对这个问题,我们希望对给定的用户群体,能知道他们的商业价值,对他们的商业价值有一个很好的描述。知道里面哪些人才是我们重点要服务的对象。
2. 用户标签的应用价值
用户标签的应用主要是四种场景:
用户特征洞察:
辅助用户分析和用户洞察,用户标签可以帮助业务人员快速的对用户有一个认知,然后发现里面显著的特征,获得一些商业灵感。
增强数据分析:
标签还可以丰富数据的维度。对我们的业务数据,有更深层次的对比分析,而分析洞察得到的灵感以后,可以辅助业务落地。
精细化运营:
一方面,可以将用户群体,切割成更细粒度的群组,使得运营从粗放化到精细化,用多种不同的手段,不同的渠道去触达,比如说短信、推送、邮件等等,对于用户进行驱动或召回,从而达到事半功倍的效果。
数据产品应用:
另一方面,除了驱动人工的业务以外,用户标签还可以成为其他数据产品的基础,比如个性化推荐系统,广告系统,CRM等这些系统。自动化的业务系统能更有效的利用这些用户标签,从而发挥更巨大的威力。
3. 为什么常见的标签体系用不起来?
用户标签其实已经不是新概念,十几年前,就已经有各种各样的标签系统,但是在我们这几年的实践过程中,其实发现,很多的标签系统在实际落地的过程中,都会多多少少的遇到一些问题。这里面主要是两大类问题。
难全面覆盖:
在创建标签的过程中,数据的提供方希望尽可能满足各种各样业务的需求,就会有一些发散性的构思,但是实际上在操作中很难覆盖特别的全面,业务是一直变化的,不能预知一年以后这个业务发展成什么样子,所以很难覆盖全。
难落地应用:
另外一大类问题,业务方在使用的时候,面对的是成百上千的甚至上万的标签,他们也比较懵,不知道怎么使用,也不知道标签的统计口径是什么,用户分层的切割规则等等这些,从而导致了不会用或者不好用,用不起来。
1. 应用驱动的标签构建
我们的解决方案其实是基于标签的应用流程,去反向去反推这个标签体系的构思和建设。
这个反推,其实是一个比较需要业务经验的事情,根据我们的经验,大部分情况下,产品部门和运营部门,都会有一些不同的标签使用方式。比如运营部门,一般是用于做活动,他们关心的问题是,怎么样做一个活动才能够提高客户的转化。而产品则是负责对某一个问题提供解决方案,他们需要观察的是客户的特征,去决定如何设计才能解决大多数的问题。
2. 根据标签的使用目的,体系化梳理标签
总体来说,无论是产品还是运营,我们都把它叫做业务部门,他们应用标签的流程实际上一般来讲就分三步。
目标人群是谁?
其实是一个战略性的问题,定位的目标人群,这里其实往往应该先看,比如说商业价值类的标签,然后去帮助我们的业务人员发现商业价值最大的那个人群。
他们喜欢什么?
如果目标人群是有比较明确的行为数据的,比如说他们是活跃用户,这时候应该去看他的用户偏好类型的这个标签,比如他喜欢做什么,然后他的兴趣爱好是什么等等这些。
如果目标人群行为数据比较少,比如说他是新用户,或者是一些静默用户,那这个时候就应该从他们所属的生命周期标签出发,去计划构建促进转化或者是召回的策略。
如何执行策略?
就是我们应该做什么,做一个什么样的策略,这个策略怎么落地?然后当策略方向有了以后,还需要一些具体的参考信息,比如推送什么时间发这种问题,需要有一些具体的营销时机类的标签,比如说用户一般的活跃时间段,然后来帮助整个计划的这个落地。
3. 标签类型
回到整个我们的标签平台本身,我们认为首先作为一个标签平台,它需要具有非常灵活的标签创建的能力,从而才能适应不断变化的业务需求。
具体来说,我们是把需要创建的这个标签分成了三个大类。
数值聚合型标签:
这类的标签就是主要是在用户维度的数值计算,主要是弥补在数据采集当中未能及时补全的一些信息。如:每个⽤户最近半年消费次数、最后⼀次消费时间、近⼀周消费的商品类别
还有一种数值聚合是实时标签,类似这种标签一般都是用于运营活动的受众的筛选。如:某活动开始时间到当前时间,⽤户的下单⾦额
分群标签:
顾名思义就是给一群人,给他们打上一个标签。
如:将累计充值⾦额超过 10000 元的⽤户标记为 「⾼价值⽤户」
如:X运营活动开始后,通过运营⻚注册下单的⽤户,则标记为 「X活动转化⽤户」
状态转化标签:
这个是我们在我们定义里面是逻辑相对来说比较复杂的一类标签,这类标签通常来说都是实时标签,对于实时性的要求都会比较高,要求是秒级分钟级的。如:通过⾏为来标记新⽤户是否为⽺⽑党。
另外一类呢就是还有一些比较复杂的运营活动,或者是从控制成本的角度来做一些运营活动。如:在规定时间内,完成运营活动中的⾄少 3 项任务,并完成领券下单转化的,则标记为「价格敏感型⽤户」。
4. 标签平台的技术需求
灵活可拓展的标签创建规则:我们需要有非常灵活可扩展的标签的规则的定义。
在有限的资源条件下支持亿级用户基数的标签生产:在相对比较有限的条件下,能够支持相对比较大的用户基数的标签生产,需要对计算或者存储方面有比较高的优化,对于系统架构来说,平台的伸缩性和这种适应性都会要求相对高一些。
离线标签按天更新,实时标签秒级延迟:对于业务,我们一般的标签可能是按天更新的,例行标签。另外有一种就是实时活动,计算的响应要求比较高,实时标签的计算要在秒级之内完成,可能秒级之内还要后面做推送,然后触达到用户。
1. 基础数据流
下面主要讲讲技术问题,首先,在我们的理解当中,标签平台是一个中间层的服务,为前台服务提供一个数据支持,然后另外一方面,标签平台它所用到的数据其实是依赖于底层的基础数据平台的原始数据。
这张图就展现了神策基础数据流平台的架构。数据流是从左到右的,最左边是所有的采集的方式,各种SDK采集了数据之后,经过数据接收系统、导入系统和存储系统,然后查询系统,最后展现。
2. 简化的数据模型
在这个流里,数据模型其实是非常简单的,基本会分成两大类:用户行为数据、用户属性数据。
用户行为表:
其实是个宽表,它里面是几个常用的维度,主要描述了什么人在什么时间,做了一件什么事。所以主要字段就是:时间、用户ID、事件、渠道、搜索关键词、商品价格等。
用户属性表:
用户属性表,主要描述用户的属性情况,相对变化不大。主要字段有:用户ID、性别、注册渠道、会员等级等。
3. 基于有限流的标签计算
所以在我们的系统里面,首先会做一套批量离线的标签处理引擎,依赖的是我们底层比较稳定的数据结构。这个标签引擎一边读事件数据,一边读用户的属性数据,再配合上特定的标签规则,做一个批量计算,最后生成用户标签。
有限流:
Event-User 数据可以理解为永不停⽌的数据流。只要业务在用,就有不断的数据进来。
批量离线计算开始时,参与计算的数据已完全⼊库。不会有还没有入库的数据。
在有限流的情况下,数据是稳定的,计算具有幂等性,不会频繁变化。与之相对的就是基于无限流的实时计算标签,在计算启动的时刻,数据还在源源不断的进来,计算不具有幂等性。所以批量标签引擎实际上跟一些离线数据仓库和离线引擎一样,最核心的两部分,一个是调度器,一个是计算引擎。
实现⽅式:
使⽤ Impala + HDFS(parquet) 为底层计算引擎
标签规则引擎负责将标签定义翻译为⾼效 SQL
使⽤ impala 分析函数实现特定的规则
通⽤调度器负责例⾏任务的调度
4. 非实时标签数据存储格式
数据存储方面,我们采取的方式是每个标签都存一张物理的表,以时间作为分区,因为离线计算一般都是按天调度的,所以就按天存储,每日的结果存为一个partition,然后这个partition下面存的都是parquet类型的文件,并且用gzip来压缩。我们这个单表里面每一行是一个用户的ID,然后后面有一列跟的是它的这个标签的值,在这种结构下用gzip一压,其实压缩比还是比较高的,比较可观。
5. 标签宽表加速查询
每个标签存一张物理表,其实也是有比较大的问题。这个表虽然在数据更新的时候很好处理,能够保持更新时的数据的一致性,但是对于查询端其实并不是很友好,尤其是在做多条件过滤的时候,需要将底层的多张表进行 join 操作,计算代价很大。为了提高性能,我们在后台会有一个例行任务,定时将这些已经固化下来的标签编号,把它合并成一张宽表,主要依据标签的离线计算,基本上每天都更新一次,更新完了以后这个数据基本上就固定保持稳定了。
标签单表:
数据更新代价低,可保证数据⼀致性
问题:查询需要多张表 join,性能堪忧
标签宽表的实现⽅式:
标签宽表是⼀个所有单表 join 的 view
每当单表数据更新时,更新该 view
定时将 view 固化为物理表
遗留问题:parquet 在列数过多的情况下,性能会有所下降
6. 用bitmap优化人群筛选
另外就是使用bitmap来做人群筛选优化,部分标签值所对应的⼈群使⽤频次更⾼,如「⾼价值⽤户」、「活跃⽤户」等。使⽤标签筛选⽤户,可以理解成针对⼈群包的集合操作。
bitmap 过滤的实现⽅式:
将标签值对应的⼈群包构建 RoaringBitmap
⼈群筛选时,先通过 bitmap 的交并差运算得到过滤⽤的 bitmap
impala 使⽤ bitmap 做最终的过滤器,得到⼈群包(包含太多元素的 bitmap 体积太⼤,反⽽影响效率)
7. 基于无限流的标签计算
大部分业务场景实际上是离线的部分就能满足了,实时的部分主要是要满足一些运营活动的一些需求。我们这个实时标签引擎其实也并不复杂,输入的数据就是我们实时流的事件数据,根据标签规则,还有用户属性,用户标签对他做在线的一个计算,从而输出的是一个标签状态的变更,最后得到这个标签结果。
8. 实时标签引擎
实现⽅式:
实时标签计算使⽤ Flink
Flink job 监听 Kafka 的 event topic,计算由事件触发
计算过程就是实现⼀个状态机
计算的中间状态存储在 Flink State 和 KV 存储中
实时计算能使⽤的离线标签,需要先订阅到 KV 存储中
标签结果输出到 Kafka 的 tag topic
9. 批流一体的架构
整体的架构就像这张图一样,在我们的标签管理控制台这一层,其实是对标签规则做了一个划分,在这里会识别当前要算的这个标签,到底是一个离线标签还是一个实时标签比较好?如果它是实时标签,它要对哪些离线标签进行订阅,也是在这里处理的。离线标签就做离线的计算,然后在最下面有一个数据同步服务,会把离线标签计算的结果同步到kv里面,这里面其实也不会依赖特别多,我们不会给他做一些特别复杂的计算,然后依赖特别多的数据,因为kv里面也会有性能问题。然后Flink State实际上是kv存储的半个缓存,实际上计算由Flink Job来进行。
最后总结一下,我们所理解的标签平台,实际上是以应用为目标来构建的标准体系。我们认为在这个平台里面标签规则一定是要灵活的,要让真正做业务的技术小白,也能够灵活的自主配置,然后能够自己搭建这个标准体系,能够自己改规则。在技术层面,标签平台它是依赖于底层特别稳定的数据模型和数据流的,然后标签平台本身它的技术架构实际上是批流一体,因为批量相对来说计算性能更高,代价更小,然后流式是实时性更高,两边一起组合而成的标签生产体系。
1. 有不少的标签计算逻辑是相似的,怎么合并这一类的相似标签生产,怎么提高效率?
首先我们的逻辑是,只要单个计算足够快,就可以不合并,所以大部分情况优化的是单个计算的性能。相似标签只在 SQL 级别做了个结果的缓存,但实际效果还不太明显。更有效的方式可能是人工介入。
2. 运营圈人的时候能否支持实时标签和离线标签的整合圈人?
这个其实是可以的,我们这个实时标签,它的输出的结果实际上到Kafka里面,Kafka后面的消费端是可以把它存到hdfs上的,然后就跟离线标签算出来的结果实际上是一样,并没有什么太多的区别。
3. 现在的实时标签目前占比大概多少?是不是不同的企业会根据业务去做一些调整?
其实在系统规划里面实时标签的占比并不高,或者说应该是比较低。一方面是从计算资源的角度来考虑,实时计算的成本会比较高。另外也是从需求方面考虑,大部分可以通过合理规划,将部分计算转为离线 & 实时相结合的方式来处理。
王琛
神策数据 | 用户画像研发部 & 武汉研发中心负责人
加入神策数据之前,王琛先生曾任职于百度大数据部高级研发工程师,参与百度日志平台、用户数据仓库、新日志标准化、Impala 查询优化等项目;曾担任百纳信息 ( 海豚浏览器 ) 研发总监、人工智能实验室负责人。王琛先生有 7 年以上大数据从业经验,硕士毕业于英国爱丁堡大学人工智能专业。