1号店用户画像系统偏好算法和Storm优化实践
导读:
1号店从零开始打造了自己的用户画像系统,包含了用户标签画像、用户偏好画像。经历了Hadoop版全量画像、Storm版实时画像、电商用户标签画像等阶段演进和完善,在两年的时间里,遇到了性能瓶颈、数据质量评估、用户标签的膨胀、画像在精准化营销等应用场景的摸索。本案例将详细介绍1号店用户画像系统实践过程中的问题及解决方案。
(全文共3600字 预计阅读时长:4分钟)
一、案例复现
启动初期,推荐系统需要从比较通用的协同过滤版本优化到个性化的千人千面,以提高GMV转换率,需要构建画像系统做支撑。
第一版开发完之后,偏好画像包括类目偏好和导购属性偏好两个部分,类目偏好逐步投入业务应用,其中偏好接口调用数每天达千万次,主要服务于推荐栏位和EDM,但偏好画像存在性能低下,偏好得分分布不合理之类的问题。详情如下:
● 运行一次全量的数据更新太慢;
● 用户的偏好得分数据分布不合理,得分呈多波峰分布,且在[6.0,8.0]区间的得分数目几乎为0;
● 用户强偏好和弱偏好的阈值界限未有明显规定;
● 部分用户反馈画像中包含用户为访问过的类目数据;
● 现有更新模式下,用户未产生新的行为,兴趣偏好分值将不会发生变化(未按时间进行衰减)。
二、解决思路
从性能上,离线部分的全量更新应在12个小时内完成;在线部分应满足高并发、低延迟,可以支撑每天上亿次的访问。
从功能上,偏好系统应包含用户对类目和热点导购属性的偏好得分,得分分布应可以正确区分出用户的偏好程度【喜欢|不喜欢】,用户行为的权重随日期衰减,并且对于画像优化和演进主要采用以下六个思路:
● 用户偏好画像权重算法的不断迭代优化;
● 引入Storm等实时技术;
● 主题推荐标签、用户命名实体等新增标签补充进画像;
● HBase的离线和在线分离、Hbase的KV读和Solr的批量读分离;
● 性能不断优化;
● 数据存储改进。
三、实践过程
● 3.1 数据架构
数据架构如图1所示。
图1 数据架构
Hedwig是1号店自主研发跨IDC调用,支持灰度发布的中间件。
● 3.2 系统流程图
系统流程图如图2所示。
图2 系统流程图
●3.3 用户偏好画像权重算法的不断迭代优化
通过优化画像的评分模型,准确反映用户对类目和导购属性的长期偏好。
偏好得分应满足的条件
● 用户在此类目或导购属性上的操作越多,得分越高;
● 用户对类目或导购属性的喜好程度不同,可以通过偏好得分区间体现;
● 用户的历史行为应有衰减。
对于类目偏好,需先将用户对类目偏好,划分为多个类别,最简单的行为可划分为两档【喜欢|一般】,并分析各自的行为规律,以调整模型参数。用户没有行为的类目,可以考虑使用MF等手段预测其得分。
参数调整的原则
● 偏好得分分布应与用户对类目的权重分布一致;
● 衰减系数的设置应满足两个月衰减一半。用户购买周期如图3所示。
● 各类行为权重的设置应满足,各权重之间的比例等同于用户各种行为数目的比例,对于属性偏好,采用了信息论模型,无需手动设置参数。
图3 用户购买周期
● 3.4引入Storm实时技术
引入Storm实时技术,如图4所示。
KafkaSpout为系统提供,只需设置好topic调用即可,OrderSpout是从Jumper中接入订单,具体逻辑就是接受一条消息后进行检查和封装发出。
TrackAnalysisiBolt接受Kafka发来的消息,使用tracker解析器进行行为解析,此部分会周期性(一天)地从redis拉数据,redis数据使用离线定时任务进行更新。
图4 引入Storm实时技术
ActionBuildBolt接受解析好的tracker,对tracker进行转换变成意图结构,这部分包括pminfid到productid的转换,商品品牌、类目的添加,会查询离线表product_intent,pm_product_intent,这个表也是周期性更新。
IntentComputeBolt为核心部分,每个tracker过来后会查询用户的意图数据,然后在更新意图并存储(redis和hbase都会存储),对应更新的表格为user_intent_exp,如表1所列。
表1 user_intent_exp
RecommenderBolt为实时推荐,接收到每个行为后会查询用户意图,然后根据意图调用user_action_weekly,查询用户的所有行为,如图5所示,进而根据用户浏览商品进行推荐,存储表为realtiem_rec。
图5 用户行为查询公式
● 3.5主题推荐标签及用户命名实体等新增标签补充进画像
主题推荐标签
主题和标签的映射关系如表2所列。
表2 主题和标签的映射关系表
使用标签表中的关键词列表,结合商品的评论、标题数据给商品打标签。
商品打标签的公式如图6所示。
图6 商品打标签公式
商品标签存储在hbase上的product_tags表,如表3所列。
表3 product_tags表
用户打标签的公式如图7所示。
图7 用户打标签公式
用户标签存储在hbase上的user_tags表,如表4所列。
表4 user_tags表
值得注意的是,在这一步需要统计平均每个用户被打上标签的数量。针对标签稀疏问题,我们可以尝试使用CF对用户标签做平滑处理。
用户命名实体识别的标签
通过用户历史订单地址做地址结构化,再对结构化中的地址做用户命名实时识别,最后对每一个用户的地址做地址匹配,即可识别出用户的公司、小区、校园标签,具体实现方法见作者在2015年qcon上的分享,识别的命名实时数目如表5所列。
表5 识别的命名实时数目表
● 3.6HBase的离线和在线分离、KV读和批量读分离
离线Hadoop任务会对数据库某段时间I/O频繁访问,影响实时的性能,把离线和实时的集群分开,如图8所示。在离线集群上应用bulkload生成HBase的源文件hfile,在实时线上集群上拉取离线集群的hfile:
Hadoop dfs -cp hftp://ip1:port/userProfileBulkLoad hdfs://ip2:port / userProfileBulkLoad
实时线上集群通过LoadIncrementalHFiles命令,补上丢失的增量数据:
HBase org.apache.Hadoop.HBase.mapreduce.LoadIncrementalHFiles / userProfile BulkLoad userProfile
这样做避免了对数据库频繁写入的压力,也避免了离线任务对实时任务的影响。
图8 离线和实时的集群分离
另外,实际生产环境中,HBase会有不少坑,离线写可以通过bulkload等批量写的方式,但是对于在线读,应避免特别大的Scan,我们把画像的数据也写在了分布式索引的Solr,对于批量读,或者二级索引可以优先走Solr,其次再考虑HBase的二级索引,减少HBase的压力,如图9所示。
图9 生产环境中的HBase
●3.7 画像性能优化
离线部分的track解析迁移至统一的行为解析数据库,在加快运行速度的同时,还可以提高行为解析的准确率。
用户行为数据设计到userid和guid:
● 在同一sessionid中,若userid出现过,则该sessionid中的所有行为对应至该userid;
● 在guid和userid的对应关系中,滤掉公用电脑和黄牛账户。
为了进一步提高离线部分的计算速度,用户的行为权重计算亦可以增量计算。
设Wh为用户对某个类目的历史行为权重,Wc为用户最新一天的行为权重,则总的行为权重为:Wt = λWh + Wc,0<λ<1
采用此权重,带入模型,计算偏好。
然后更新Wh = Wt。
如果采用上述方法,则不必列出用户的所有行为数据,每次更新时,只需列出一天的数据即可。
● 3.8数据存储优化
画像离线与在线数据的存储结构
●离线的数据结构采用Hive
●在线的数据存储:第一版画像的数据存储在Hbase中,每天可支撑数千万次的访问,时延10ms左右,性能尚可,并且存储的数据量是TB级,如果用传统的数据库,随着标签急速的增加,势必要不停的分表,存储的扩展性不是很好,新版画像的在线存储系统仍然使用HBase。考虑到类目偏好使用比较频繁,而导购属性偏好数据量远大于类目偏好,将两者分开存储。
类目偏好离线数据结构-Hive如表6所列。
表6 类目偏好离线数据结构-Hive
离线的全量数据进行过滤之后,导入在线部分。过滤原则:
● 每个用户的偏好类目数量小于一个固定值;
● 用户偏好得分大于下限,该下限可假设用户当天在某个类目只有一个加车行为,然后带入模型反推出来
类目偏好在线数据结构-HBase
Rowkey: userid
ColumnFamily:category_level
Column:category_id
Value: weight
导购属性偏好离线数据结构-Hive如表7所列。
表7 导购属性偏好离线数据结构-Hive
离线的全量数据进行过滤之后,导入在线部分。过滤原则:
● 属性偏好大于一个固定的下限;
● 属性值的数量小于一个上限;
● 属性值偏好大于一个固定下限。
四、 效果评价
● 画像系统使得公司广告投放ROI提升3%;
● 实时画像(意图)对猜你喜欢栏位的共享占比60%多;
● 首页大轮播的GMV提升3‰;
● 应用到首页猜你喜欢、团购、闪购、搜索、推荐、营销等栏位或者产品;
● 了解受众群体的变迁,适时推出适合的产品;
● 降低自营商品的采购数量,指导了厂商优化产品结构;
● 基于标签画像的千人千面上线效果,如图10所示。
图10 人群细分推荐转化效果分析
五、推广建议
● 提炼出该案例(或项目)的哲理、方法论。
● 算法准确度、数据规模、更新速度相互制衡,提高某些指标,必须牺牲其他指标。
● 一个系统遇到性能瓶颈的时候,适度分解系统,以满足不同场景。
● 系统给在线栏位用的时候,一定得考虑降级和延迟环境。
● 数据流各个环节都可能出错,自动化检查各个节点的中间数据。
● 系统演进的时候,有不同的方案,争取多数人支持,减少一个人拍板的方案。
● 不同版本开发的时候,适度换些开发者,融入新的思路,避免少数人思维定式。
● 避免运营驱动,不同时期,过来新的标签需求,如果研发团队只管添加,大部分标签会沉睡,后面基本用不到。研发团队首先确定自己的标准和规范,以筛选新需求的标签和排优先级
● 数据驱动,通过观察和研究数据,对数据有一定的敏感度,产生新的用户画像数据。
★★征稿★★
寻找100个年度最具价值的实践案例
我们只要案例干货,拒绝广告
成为特约作者,你将:
◆ 连接100名年度经验与增长值TOP100的研发精英
◆ 提前入围「壹佰案例」年度最优案例榜单
◆ 案例整理成册,出版发行图书
◆ 成为msup客座教练
◆ 以观察员身份受邀出席壹佰案例
◆ 所在公司享有msup活动优惠
有意者关注「壹佰案例」