用户标签计算系统设计
实时计算部分参考自博文:
用户标签系统的用途
用户分类,精准营销。
标签的定义
我司常用的标签有:新用户、老用户、流失用户、活跃用户等。此外,还可以根据用户以往行为,如投诉、订单取消、查看报价等,为用户打上相应的标签。标签系统提供了从多维度进行用户分类的方法 。在用户分类的基础上,实现差异化营销、差异化优惠,则可以节约营销成本。
标签的时效性
标签如新用户、流失用户等 ,会随用户在系统中下单而失效。而活跃用户会随着用户在系统中长期不下单而变成流失用户。通常,用户半年以前的行为参考性较低。用户标签需要根据用户近期行为生成。因此,标签必须与用户的实际状态同步,从而不误导营销决策。
标签的使用需求
使用标签的需求有2种:
- 第一种是给定一个用户,问用户是否具有某标签。在给用户发放代金券时,用户标签可用于决定券的金额、券种。此种情况下,用户标签必须是实时的。
- 第二种是给定一些标签,问具有这些标签的用户有哪些。在节假日、重大营销节点时,可通过为指定特征的用户集中推送优惠信息,实现促销。在这种情况下,用户标签为准实时即可。
总而言之就是:从用户角度查询;从标签角度查询
实时计算用户标签
为用户打上标签本质上是为识别用户的某种历史行为特征并标记出来。由于标签的时效性要求,需要分析用户近期的行为。因此,我们将用户的行为作为基本的记录、分析单位。
一条记录的例子如下:
用户Id | 发生时间 | 行为类型 | 订单Id | 其它 |
---|---|---|---|---|
123 | 2016-10-20 12:10:32 | 取消订单 | orderId | ..... |
每当用户进行某个行为时,则为用户添加一条记录。为方便实现更多的查询、搜索扩展,我们把用户行为数据实时导入到Elasticsearch中。
当计算给定用户标签时,从elasticsearch/数据库中查询到指定时间段内用户行为,实时为用户计算标签返回。
由于用户行为是实时导入的,而用户标签是根据用户最新行为记录生成的,因此生成的标签具有实效性。由于每个用户在一段时间内的订单相关行为数据量不大,因此计算开销可以忽略。
以上设计的好处在于,我们可以随时调我们生成标签所关心的时间段。可以关心最近3个月,或者突然改到半年。而标签的定义也可以随时更改。底层是最原始的用户行为数据,不需要任何改变。
准实时标签查询用户
根据标签查询用户则要困难一些。我们必须提前为每个用户计算好标签。才可以根据标签建立索引,最后实现查询。在数据量较大的情况下,计算一次可能需要1-2天。如果只在少量时间节点使用此功能,这样的时间开销可以接受。
我们考虑如果需要经常使用此功能,如何实现 ?
由于我们已经有了实时计算给定用户标签的能力。因此,每当用户有新的行为时,我们可以重新为此用户计算标签,并入库。系统运行一段时间之后,在系统中有行为的用户在数据库中都有了记录。行为越频繁的用户,其标签状态越实时。
为了保证用户标签不过时,我们记录用户标签的更新时间。通过逐条扫库的方式,更新数据库中更新时间较为久远的数据,重新计算标签。
由于用户最新的行为会导致标签更新,因此扫库的方式只是为了保证标签不会因为时间的推移而过时。这方面的时效性要求在一周,一天以内都可以接受的。
用户行为的监听
一种监听用户行为的方法是通过异步消息。用户的行为会在不同的服务器中发生。当服务器检测到相关的事件时,通过消息系统发出消息通知,从而告知标签系统。然而采用消息系统实现有以下2个问题:
- 需要其它系统配合发出消息
- 如果消息丢失、消息重复则标签计算不准确
消息重复的问题可以通过去重来解决,而其它问题则无法解决了。
因此我们想到采用canal,通过监听数据库的变化,来得知订单状态变更的事件。这样,不需要其它系统的配合,需要完成事件的可靠监听。
总结
我们阐述了一种实现实时标签系统的方法。通过存储用户的历史行为,我们的底层系统具有了以不变应万变的能力。通过实时计算标签,用户标签的定义就可以随时修改了。通过将用户行为放入elasticsearch中,加快了用户行为查询的速度。
另一方面,通过实时重新计算用户标签,我们保证了用户标签根据用户行为实时调整。而对于标签的随时间推移过时问题,我们通过扫库的方式来逐渐更新。从而做到了用实时更新应对快速变化,用后台任务应对慢速化。
下面是我的补充:
用户标签的离线计算体系
我司目前有很多用户标签都是都是通过离线数据分析计算出来的,比如:散单高频用户(散单:非包月包年套餐,高频:每月内连续下单超过3次)、余额不足(会员卡内余额小于50)、沉睡用户(会员卡余额大于200,但近30天内有完成单,近14天未创建订单)等。这些标签都是可以通过各个业务表内的数据 进行汇总计算出来的。所以,我们的方案是定期同步相关数据表到Hive数据表中,然后使用Hive SQL对数据进行离线数据分析,然后将数据清洗到现有的用户标签相关数据表中。