作者:杨承波
GrowingIO 大数据工程师,主要负责 SaaS 分析和广告模块的技术设计与开发,目前专注于 GrowingIO 物化视图引擎的建设。
本篇文章主要讲解基于 GrowingIO 内部数据存储结构 Bitmap 实现的 Percentile,并简单介绍一下 Hive Percentile,Spark Percentile,Bitmap Percentile 之间的差异。
讲解具体函数算法实现之前,先搞清楚下面两个问题:
-
Percentile 函数【以下简称:分位数】,在实际应用场景下的作用是什么?
-
今天你是否还想起,Bitmap 是什么东西?
1. 分位数是个什么玩意儿🔢
1.1 分位数
😱分位数是啥?
针对一个从小到大的有序集合,找一个数来将集合按分位对应比例拆解成两个集合。
注意:分位数并非是指数据集合中的某个元素,而是找到一个数来拆解集合
🤔 来点儿晕头转向的东西,90 分位怎么出?
这个数将样本集合分成左右两个集合,而且左边部分的集合占 90%,右边部分占 10%
①元素个数为奇数的集合如何求 90 分位数?
原始集合:【35, 40, 41, 44, 45, 46, 49, 50, 53, 55, 58】
拆解集合:【35, 40, 41, 44, 45, 46, 49, 50, 53】, 55, 【58】
左边集合元素个数:9
右边集合元素个数:1
正好在原始集合中有这个数能将样本按 90 分位比例拆解成两个集合
所以上面样本的 90 分位是 55
②如果换成元素个数为偶数的集合呢?
原始集合:【40, 41, 44, 45, 46, 49, 50, 53, 55, 58】
拆解集合:【40, 41, 44, 45, 46, 49, 50, 53, 55】, X, 【58】
这个数存在于 【55 → 58】
X = 58 - (58 - 55) * 0.9 = 55.3
或 X = 55 + (58 - 55) * (1 - 0.9) = 55.3
90 分位含义:有90%的数据小于等于 55.3,有 10% 的数据大于等于 55.3
1.2 在业务场景中的应用
👉现有【订单支付成功】事件,获取过去七天每个用户做过该事件总次数的 90 分位值,如下图:
👉还是【订单支付成功】事件,获取昨天每个用户在该事件下实际购买金额的总和,求 75 分位值,如下图:
2. Percentile 哪家强?
2.1 性能对比
环境准备:Core[16], 内存 2G
对比测试:[基于Bitmap实现的Percentile] VS [SparkSQL内置Percentile_approx]
场景:一定数量的用户以及随机生成对应的count,随机生成分位进行计算分位数,获取百次平均消耗
x 轴含义: 数据量
y 轴含义: 计算时间, 单位毫秒。
-
SparkSQL 中 Percentile 仅支持 Int, Long 数据类型,这里为通用考虑,使用 Percentile_approx 进行对比
-
以上 Bitmap 存储数据与 Percentile_approx 处理数据完全一致
2.2 Hive Percentile
Hive Sql 中 Percentile 求解时针对的是一列进行操作,即表里的某一个字段,面对动不动几千万的数据处理,如