一. 需求背景
目前标签平台的技术需求大体归纳如下:
1.灵活可扩展的标签创建规则或者人群分群规则: 我们需要有非常灵活可扩展的标签的规则定义和分组分群。
2.支持亿级用户技术的标签生产:在技术设计考虑系统未来发展,能够支持相对较大的用户技术的标签生产,需要对计算或者存储方面要求较高,对于系统架构来说,平台的伸缩和适应性都要求相对高一些。
3.理想标签按天更新,实时标签秒级延迟:对于业务,我们一般的标签可以按照天更新。但考虑未来发展和业界动态,有实时标签的应用和场景需求,计算要求秒级响应,可能在秒级之后做推送,然后触达用户。
二. 技术方案设计
标签平台是一个中间层的服务,为前台提供的是数据支持。另外一方面标签平台的加工,依赖底层的基础数据平台的原始数据。包含:
1. 建立数据模型
基于原始数据加工,简化对应的数据模型,可以分为两大类,用户行为数据和用户属性相关的数据。
对于数据建模,可以阅读文章:多维用户行为模型
对于OneId的开发,可以阅读文章:基于Spark Graphx实现ID-Mapping
2. 标签计算技术架构
主要涉及标签管理控制台,除了对标签元数据(标签名称,标签规则,标签状态)管理外,也对标签计算逻辑相似,或者合并等进行人工介入,进行审核管理。剩下就是离线批处理数据计算加工任务,后续扩展实时加工任务。
2.1 数据流程说明
①. 基于OneId表,用户属性表,用户行为表和标签元数据表对应标签计算加工,产生独立的标签加工任务,避免互相影响;
②. 基于标签加工任务,结果存储选择每个标签都存储一张物理表(标签相互不干扰),以时间为分区,每天产生一个partition, 使用parquet的数据格式,并且使用gzip压缩。因为通常该标签表下面只有两列,一列是用户id,一列是标签值,所以压缩比还是比较高,比较客观;
③. 基于独立标签表,进行宽表加工加速查询,因为使用标签单表的优势:标签更新代价低,保证该标签数据一致性。 缺陷就是查询需要多张表join,性能比较低。使用提前join产生一张宽表:通常实现方式是:
- 建立hive的视图,有标签表更新则更新该视图,然后定时将该视图固化为物理表(视图的查询实际还是在join);
- 建立Hbase表的方式,hbase表支持横向扩展n列,避免hive使用parquet 列很多的时候性能下降,同时基于hbase的row key, 列的批量写入很高效;
- 建立ES索引表的方式,通过对每个标签表映射为es的索引,方便检索和查询,同时也方便进行聚合计算。
2.2 标签表查询
当宽表构建完成后,通常基于标签组合进行人群筛选,除了常规对使用频率高的标签列建立索引或者索引表外,还可以使用bitmap进行人群优化。例如:
①. 将标签值对应的人群构建Roaring Bitmap;
②.人群筛选时,先通过bitmap的交并差运算得到过来的bitmap;
③. 查询接口使用bitmap做最终的过来,但也要考虑查询影响(包含太多元素的bitmap体积太大,拖累查询反应效率)。
通常有三种方式做离线标签加工: 1. 使用每个标签单独的一张表,缺点是多标签查询的时候需要join,效率低;
2. 使用一张标签存储所有的标签,分区字段label=label_name,但是标签值通常有数值,字符串,日期(也可以转换为数值),枚举等,所以根据元数据,不同的标签对应不同的值,则对应user_id, label_int_value, label_varchar_value ... 中存储对应标签值。 缺点就是有很多分区字段;
3. 在单个标签单个表的基础上使用一个存储引擎,如hbase(基于user_id的主键做标签合并),在增加一个能够做标签多维查询的引擎(如es,通过标签名 多条件查询 user_id)的方式做应用,当然也可以考虑 即能够做点查询(hbase) 也能够做多维查询的组件。