查看原文
其他

小程序是如何设计百亿级用户画像分析系统的?

钟文波 腾讯云开发者 2023-05-15


导语 |  We 分析是微信小程序官方推出的、面向小程序服务商的数据分析平台,其中画像洞察是一个非常重要的功能模块。微信开发工程师钟文波将描述 We 分析画像系统各模块是如何设计,在介绍基础标签模块之后,重点讲解用户分群模块设计。希望相关的技术实现思路,能够对你有所启发。


目录

1 背景介绍   1.1 画像系统简述   1.2 画像系统设计目标2 画像系统整体概述3 基础标签模块   3.1 功能描述   3.2 技术实现4 用户分群模块   4.1 功能描述   4.2 人群包实时预估   4.3 人群创建   4.4 人群跟踪应用5 总结



01



背景介绍


   1.1 画像系统简述


We 分析是小程序官方推出的、面向小程序服务商的数据分析平台,其中画像洞察是一个重要的功能模块。该功能将为使用者提供基础的画像标签分析能力,提供自定义的用户分群功能,从而满足更多个性化的分析需求及支撑更多的画像应用场景。

在此之前,原有 MP 的画像分析仅有基础画像,相当于只能分析小程序大盘固定周期的基础属性,而无法针对特定人群或自定义人群进行分析及应用。平台头部的使用者均希望平台提供完善的画像分析能力。除最基础的画像属性之外,也为使用者提供更丰富的标签及更灵活的用户分群应用能力。因此, We 分析在相关能力上计划进行优化。

   1.2 画像系统设计目标


  • 易用性:易用性主要指使用者在体验画像洞察功能的时候,不需要学习成本就能直接上手使用。使用者可以结合自身业务场景解决问题,做到开箱即用 0 门槛。

  • 稳定性:稳定性指系统稳定可靠体验好。例如画像标签数据、人群包按时稳定产出,在交互使用过程中查询速度快,做到如丝般顺滑的手感。

  • 完备性:指数据丰富、规则灵活、功能完善;支持丰富的人群圈选数据,预置标签、人群标签、平台行为、自定义上报行为等。做到在不违反隐私的情况下平台基本提供使用者想要的数据。

整体来看,平台支持灵活的标签及人群创建方式,使用者按照自己的想法任意圈选出想要的人群,按不同周期手动或自动选出人群包。此外也支持人群的跟踪分析,人群在多场景的应用等。




02



画像系统整体概述

系统从产品形态的角度出发,在下文分成2个模块进行阐述——分别是基础标签模块及用户分群模块


  • 多源数据:数据源包括用户属性、人群标签、平台行为数据、自定义上报数据。

  • 画像加工:主要是对用户属性、人群标签、平台行为,进行相应的 ETL(Extract Transform  Load ,提取转换加载)及预计算。

  • 人群计算:根据使用者定义的用户分群规则,从多源数据中计算出对应的人群。

  • 画像导入:画像及人群数据在 TWD 加工好后,从 TWD 分布式 HDFS 集群导入到线上的 TDSQL 、 ClickHouse 存储;其中,预计算的数据导入到线上 TDSQL 存储,用户行为等明细数据导入到线上 ClickHouse 集群中。

  • 画像服务:提供在线的画像服务接口。其中标签管理使用通用配置系统,数据服务采用 RPC 框架开发,在上一层是平台的数据中间件。此处也统一做了流量控制、异步调用、调用监控、及参数安全校验。

  • 画像应用:提供基础标签分析及针对特定人群的标签分析,另外还提供人群圈选跟踪分析及线上应用等。




03



基础标签模块


   3.1 功能描述


该模块主要满足使用者对画像的基础分析需求,预期能满足绝大部分中长尾使用者对画像的使用深度要求。主要提供的是针对小程序大盘的基础标签分析,及针对特定人群(如活跃:1天活跃、7天活跃、30天活跃、180天活跃)的特定标签分析。如下所示:


   3.2 技术实现


   3.2.1 数据计算


从上述功能的描述,可以看出功能的特点是官方定义数据范围可控,支持的是针对特定人群的特定标签分析。

针对特定人群的特定标签分析数据是用离线 T + 1 的 hive 任务进行计算。流程如下。

分别计算官方特定标签的统计数据、特定人群的统计数据,以及计算特定人群交叉特定标签的数据。


   3.2.2 数据存储


不同存储对比存在差异。在上述分析之后,需要存储的是预计算好的结果数据。此外,业务的特点是按照小程序进行多个数据主题统计的存储,所以第一直觉是适合用分布式 OLTP 存储。团队也对比了不同的数据库,在选型过程中,主要考虑对比的点包括数据的写入、读取性能。


  • 写入包括是否可以支持快速的建表等 DDL 操作。平台数据指标多,例如 We 分析平台数据指标近千个。
    不同的场景主题指标一般会分别进行计算,写入到不同的在线存储数据表中,所以这需要具备快速 DDL 及高效出库数据的能力。

  • 读取包括查询性能、读取接口是否简单灵活、开发是否简单;以及相关运维配套设施是否完善,如监控告警、扩容、权限、辅助优化等。



从上图和 Datacube / FeatureKV / HBase 的对比可以发现 TDSQL 更符合此业务诉求、更具备优势。


因此 We 分析平台基本所有的预计算结果数据,最终选用 TDSQL 来存储离线预计算结果数据,关于 TDSQL 的几个关键点如下:


  • 存储容量:We 画像分析系统采用的 TDSQL 服务中,当前支持最大 64 个分片,每个分片最大 3 T ,单个实例最大能支持存储 192 T 的数据。

  • 数据出库:通过数平 US 上的出库组件可以完成数据从 TDW 直接出库到 TDSQL ,近 1 亿数据量可以在 40 min + 完成出库,出库组件的监控及日志完善。



  • 查询性能:2 个分片,8 核 32 G 进行测试,查询某小程序一段时间数据,查询  QPS 5 W。

  • 读取方式:通过 jdbc 连接查询,拼接不同 sql 进行查询,查询方式简单灵活。

  • 运维方面:实例申请 、 账号设置 、 监控告警 、 扩容和慢查询分析等能力,都可以开发自助在云控制台完成。

  • 开发效率:DDL 操作简单,数据开发从建表到出库基本没有学习成本,问题定位简单高效。

当前整个平台的预计算数据出库到 TDSQL 的数据达到十亿级别,数据表超百张,实际使用存储上百 T 。TDSQL 整体功能较为全面,开发者仅需要补充开发数据生命周期管理工具,删除方式的注意点跟 MySQL 一样。

如果采用 KV 类型的引擎进行存储,需要根据 KV 的特性合理设计存储 Key 。在查询端对 Key 进行拼接组装,发送 BatchGet 请求进行查询。整个过程开发逻辑会相对繁复些, 需要更加注重 Key 的设计。若要实现一个只有概要数据的趋势图,那么存储的 Key 需要设计成类似格式:{日期} # {小程序} # {指标类型} 。




04


用户分群模块


   4.1 功能描述


该模块主要提供自定义的用户分群能力。用户分群依据用户的属性及行为特征将用户群体进行分类,以便使用者对其进行观察分析及应用。自定义的用户分群能够满足中头部客户的个性化分析运营需求,例如客户想看上次 618 参加了某活动的用户人群,在接下来的活跃交易趋势跟大盘的差异对比;或者客户想验证对比某些人群对优惠券的敏感程度、圈选人群后通过 AB 实验进行验证。上述类似的应用会非常多。

在功能设计上,平台需要做到数据丰富、规则灵活、查询快速,需要支持丰富的人群圈选数据,并且预置标签、人群标签、平台行为、自定义上报行为等。支持灵活的标签及人群创建方式,让客户能按照自己的想法任意圈选出想要的人群,按不同周期手动或自动选出人群包,支持人群的跟踪分析、人群在多场景的应用能力。

   4.2 人群包实时预估


人群包实时预估是根据使用者客户定义的规则,计算出当前规则下有多少用户命中了该规则。产品交互通常如下所示:


   4.2.1 数据加工


为了满足客户能随意根据自己的想法圈出想要的人群,平台支持丰富的数据源。整体画像的数据量较大,其中预置的标签画像在离线 HDFS 上的竖表存储达近万亿/天,平台行为百亿级/天,且维度细,自定义上报行为百亿级/天。

怎么设计能节省存储同时加速查询是重点考虑的问题之一。大体的思路是:对预置标签画像转成 Bitmap 进行压缩存储,对平台行为明细进行预聚合及对维度枚举值进行 ID 自增编码,字符串转成数据整型节省存储空间。同时在产品层面增加启用按钮,开通后导入近期数据,从而控制存储消耗,具体细节如下。

属性标签数据通常建设用户画像的核心工作就是给用户打标签,标签是人为规定的高度精炼的特征标识,如性别、年龄、地域、兴趣,也可以是用户的一些行为集合。这些标签集合抽象出一个用户的信息全貌,每个标签分别描述该用户的一个维度,各标签维度间相互联系,构成对用户的整体描述。当前的用户属性及人群标签是由平台方提供,由平台每天进行统一的加工处理生成官方标签。平台暂时没有支持用户自定义的标签,因此这里主要说明平台标签是如何计算加工管理。


  • 第一,标签编码管理。

例如活跃标签 10002 ,对标签的每个标签值进行编码如下:


对特定人群进行编码,基准人群是作为必选的过滤条件,用于限定用户的范围:


  • 第二,标签离线存储。
标签数据在离线的存储上,采用竖表的存储方式。表结构如下所示,标签之间可以并行构建相互独立不影响。采用竖表的结构设计,好处是不需要开发画像大宽表,即使任务出现异常延时也不会影响到其它标签的产出。而画像大宽表需要等待所有画像标签均完成后才能开始执行该宽表数据的生成,会导致数据的延时风险增大。当需要新增或删除标签时,需要修改表结构。因此,在线的存储引擎是否支持与离线竖表模式相匹配的存储结构,成为很重要的考量点。

采用大宽表方式的存储如 Elasticsearch 和 Hermes 存储,等待全部需要线上用到的画像标签在离线计算环节加工完成才能开始入库。而像 ClickHouse 、Doris 则可以采用与竖表相对应的表结构,标签加工完成就可以马上出库到线上集群,从而减小因为一个标签的延时而导致整体延时的风险。

CREATE TABLE table_xxx(
    ds BIGINT COMMENT '数据日期',
    label_name STRING COMMENT '标签名称',
    label_id BIGINT COMMENT '标签id',
    appid STRING COMMENT '小程序appid',
    useruin BIGINT COMMENT 'useruin',
    tag_name STRING COMMENT 'tag名称',
    tag_id BIGINT COMMENT 'tag id',
    tag_value BIGINT COMMENT 'tag权重值'
)
PARTITION BY LIST( ds )
SUBPARTITION BY LIST( label_name )(
    SUBPARTITION sp_xxx VALUES IN ( 'xxx' ),
    SUBPARTITION sp_xxxx VALUES IN ( 'xxxx' )
)

  • 第三,标签在线存储。
如果把标签理解成对用户的分群,那么符合某个标签的某个取值的所有用户 ID(UInt类型) 就构成了一个个的人群。Bitmap 是用于存储标签-用户的映射关系的、非常理想的数据结构,最终需要的是构建出每个标签的每个取值所对应的 Bitmap。例如性别这个标签组,背后对应的是男性用户群和女性用户群。

性别标签:男 -> 男性用户人群包,女 →女性用户人群包。

平台行为数据是指官方进行上报的行为数据,例如访问、分享等行为数据,使用者不需要进行任何埋点等操作。团队主要是会对平台行为进行预聚合,计算同一维度下的 PV 数据,已减少后续数据的存储及计算量。


同时会对维度枚举值进行 ID 自增编码,目的是减少存储占用,写入以及读取性能;从效果来看,团队对可枚举类型进行字典 ID 编码对比原本字符类型能节省60%的线上存储空间,同时相同数据量条件下带来 2 倍查询速度提升。


自定义上报数据是使用者自己埋点进行数据的上报,上报的内容包括公共参数及自定义内容,其中自定义内容是 key-value 的格式,在 OLAP 引擎中,团队会将客户自定义的内容转成 map 结构类型进行存储。


   4.2.2 数据写入存储


  • 在线OLAP存储选型:

首先讲下,在线 OLAP 存储选型。标签及行为明细数据的存储引擎选型对于画像系统至关重要,不同的存储引擎决定了系统不同的设计方式。业务团队调研了解到,行业内建设画像系统时有多种不同的存储方案。团队对常用的画像 OLAP 引擎做了对比,如下:



综合上述调研,团队采用 ClickHouse 作为画像数据存储引擎。在 ClickHouse 中使用 RoaringBitmap 作为 Bitmap 的解决方案。该方案支持丰富的 Bitmap 操作函数,可以十分灵活方便的判重和进行基数统计操作,如下所示。


采用 RoaringBitmap(RBM) 对稀疏位图进行压缩,可以减少内存占用并提高效率。该方案的核心思路是,将 32 位无符号整数按照高 16 位分桶,即最多可能有 216=65536 个桶,称为 container。存储数据时,按照数据的高 16 位找到 container (找不到则会新建一个),再将低 16 位放入 container 中。也就是说,一个 RBM 就是很多 container 的集合,具体参考高效压缩位图 RoaringBitmap 的原理与应用。

  • 数据导入线上存储:

接下来讲讲,数据导入线上存储。在确定了采用什么存储引擎存储线上数据后,团队需要将离线集群的数据导入到线上存储。其中对于标签数据通常的做法是将原始明细的 id 数据直接导入到 ClickHouse 表中,再通过创建物化视图的方式构建 RBM 结构进行使用。


然而,业务明细数据非常大,每天近万亿。这样的导入方式给 ClickHouse 集群带来了很大资源开销。而通常业务团队处理大规模数据都是用 Spark 这样的离线计算框架来完成处理。后团队把预处理工作全部交给了 Spark 框架,这种方式大大的减少了写入的数据量,同时也减少了 ClickHosue 集群的处理压力。


具体步骤是 Spark 任务首先会按照 id 进行分片处理,然后对每个分片中标签的每个标签值生成一个 Bitmap ,保证定制的序列化方式与 ClickHouse 中的 RBM 兼容。其中通过 Spark 处理后的 Bitmap 转成 string 类型,然后写入到线上的标签表中,在表中业务团队定义了一个物化列字段,用于实际存储 Bitmap。在写入过程中会将序列化后的 Bitmap 字符串通过 base64Decode 函数转成 ClickHouse 中的 AggregateFunction (groupBitmap, UInt32) 数据结构。

具体表结构如下:

CREATE TABLE xxxxx_table_local on CLUSTER xxx
(
    `ds` UInt32,
    `appid` String,
    `label_group_id` UInt64,
          `label_id` UInt64,
          `bucket_num` UInt32,
    `base64rbm` String,
         `rbm` AggregateFunction(groupBitmap, UInt32) MATERIALIZED base64Decode(base64rbm)
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/xxx_table_local', '{replica}')
PARTITION BY toYYYYMMDD(toDateTime(ds))
ORDER BY (appid, label_group_id, label_id)
TTL toDate(ds) + toIntervalDay(5)
SETTINGS index_granularity = 16

  • 存储占用问题:

值得关注的还有存储占用问题。标签类型数据用 Bitmap 类型存储,平台行为采用编码方式存储,存储占用大幅减少。


   4.2.3 数据查询


数据查询方式:人群圈选过程中,如何保障大的APP查询、在复杂规则情况下的查询速度?团队在导入过程中对预置画像、平台行为、自定义上报行为,均按相同分桶规则导入集群。这保证一个用户仅会在同一台机器,查询时始终进行本地表查询,避免进行分布式表查询。



对于查询性能的保障,团队始终保证所有查询均在本地表完成。上面已经介绍到数据在入库时,均会按照相同用户 ID 的 hash 分桶规则出库到相应的机器节点中。使用维度数字编码,测试数字编码后对比字符方式查询性能有2倍以上提升。对标签对应的人群转成 Bitmap 方式处理,用户的不同规则到最后都会转成针 Bitmap 的交并差补集操作。

对于平台行为,如果在用户用模糊匹配的情况下,会先查询维度 ID 映射表,将用户可见维度转化成维度编码 ID,后通过编码 ID 及规则构建查询 SQL。整个查询的核心逻辑是根据圈选规则组合不同查询语句,然后将不同子查询通过规则组合器最终判断该用户是否命中人群规则。

基于rpc开发服务接口:查询的服务接口采用 rpc 框架进行开发。

在数据服务的上一层是团队的数据中间件,统一做了流量控制、异步调用、调用监控及参数安全校验,特别是针对用户量较大的 app 在多规则查询时,耗时较大,因此业务团队配置了细粒度的流量控制,保障查询请求的有序及服务的稳定可用。

查询性能数据:不同 DAU 等级小程序查询性能。


从性能数据看,对用户量大的 app 来说,在规则非常多的情况下还是要大几十秒,等待这么长时间体验不佳。因此对于这部分用户量大的 app,业务团队采用的策略是抽样。通过抽样,速度能得到非常大的提升,并且预估的准确率误差不大,在可接受的范围内。

   4.3 人群创建


   4.3.1 人群实时创建


人群包实时创建类似上面描述的人群大小实时预估,区别是在最后人群创建是需要将圈选的人群包用户明细写入到存储中,然后返回人群包的大小给到用户。同样是在本地表执行,生成的人群包写入到同一台机器中,保持分桶规则的一致。

   4.3.2 人群例行化创建


客户创建的例行化人群包,需要每天计算。如何持续跟踪分析趋势,并且不会对集群造成过大的计算压力?团队的做法利用离线超大规模计算的能力,在凌晨启动所有人群计算任务,从而减小对线上 ClickHouse 集群的计算压力。所有小程序客户创建的例行化人群包计算集中到凌晨的一个任务中进行,做到读一次数据,计算完成所有人群包,最大限度节省计算资源,详细的设计如下:


首先,团队会先将全量的数据(标签属性数据+行为数据)按照小程序粒度及选择的时间范围进行过滤,保留有效的数据;

其次,对数据进行预聚合处理,将用户在一段时间范围的行为数据,标签属性镜像数据按照小程序的用户粒度进行聚合处理,最终的数据将会是对于每个小程序的一个用户仅会有一行数据;那么人群包计算,实际上就是看这个用户在某个时间范围内所产生的行为、标签属性特征是否满足客户定义的人群包规则;

最后,对数据按用户粒度聚合后进行复杂的规则匹配,核心是拿到一个用户某段时间的行为及人群标签属性,判断这个用户满足了用户定义的哪几个人群包规则,满足则属于该人群包的用户。

   4.4 人群跟踪应用


   4.4.1 人群跟踪分析


在按照用户规则圈选出人群后,统一对人群进行常用指标(如活跃、交易等指标)的跟踪。整个过程用离线任务进行处理,会从在线存储中导出实时生成的人群包,以及离线批量生成的定时人群包,汇总一起,后关联对应指标表,输出到线上 OLTP 存储进行在线的查询分析。其中,导出在线人群包会在凌晨空闲时间进行,通过将人群 RBM 转成用户明细 ID。

具体方法为:arrayJoin(bitmapToArray(groupBitmapMergeState(rbm)))。


   4.4.2 人群基础分析


人群基础分析对一个自定义的用户分群进行基础标签的分析,如该人群的省份、城市、交易等标签分布。人群行为分析,分析该人群不同的事件行为等。

   4.4.3 实验人群定向


在 AB 实验中的人群实验,使用者通过规则圈选出指定人群作为实验组(如想验证某地区的符合某条件的人群是否更喜欢参与该活动),跟对照组做相应指标的对比,以便验证假设。




05‍


总结‍

本篇回顾了 We 画像分析系统各模块的设计思路。在基础模块中,业务团队根据功能特性,选用了腾讯云 TDSQL 作为在线数据的存储引擎,将所有预计算数据都使用 TDSQL 进行存储。在人群分析模块中,为了实现灵活的人群创建、分析及应用,业务团队使用 ClickHouse 作为画像数据的存储引擎,根据该存储的特性进行上层服务的开发,以达到最优的性能。

后续,小程序 We 画像分析系统在产品能力上会持续丰富功能及体验,同时扩展更多的应用场景。以上是 We 画像分析系统模块设计与实现思路的全部内容,欢迎感兴趣的读者在评论区交流。

-End-
原创作者|钟文波‍‍‍
技术责编|钟文波、谢慧志‍‍‍‍‍‍

你可能感兴趣的腾讯工程师作品
| ChatGPT深度解析:GPT家族进化史腾讯工程师聊 ChatGPT 技术「文集」| 微信全文搜索耗时降94%?我们用了这种方案10w单元格滚动卡顿如何解决?腾讯文档的7个秘笈技术盲盒:前端后端AI与算法运维工程师文化
后台回复“小程序”,领本文作者推荐的更多资料
🔹关注我并点亮星标🔹
工作日晚8点 看腾讯技术、学专家经验

赞|分享|在看 传递好技术



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存