bitmap实践-留存计算

目录

  • 1. 介绍
  • 2. 留存问题
  • 3. 思路解析
  • 4. 逻辑
    • 4.1 b表建设
    • 4.2 留存计算
    • 4.3 近X天的访问天数
  • 5.分析

1. 介绍

bitmap方法是数据压缩使用的常用算法,当字段有明确上下界的时候,使用位图模式来减少存储。在业务指标体系中特别适合通用型留存指标的计算。

2. 留存问题

我们常写的留存率指标:次留/3留/7留/15留/30留,实际上都是一个公式:

第N日留存率公式 = (T日访问用户)∩ (T+N日访问用户) / (T日访问用户)

那么一般情况下,我们怎么写呢:
select user_id from 访问表 where ds=T 交集
select user_id from 访问表 where ds=T+N 除以
select user_id from 访问表 where ds=T

设计也很简单,每一个bit位代表每一天的访问,最低位代表今天;
比如 0001 就代表最近4天只有今天来访,0101 就代表最近4天有2天来访问,分别是今天和前天

bitmap访问分布 = sum(今日访问 UNION ALL 左移位(昨日访问表))
特别注意:对bitmap做了上限控制,vst_bit_31d&(pow(2,N)-1) 防止溢出。2147483647=pow(2,31)-1表示最近31天的数据

3. 思路解析

bitmap实践-留存计算_第1张图片

  1. 通常我们计算次日留存,按照正向思考是当天来访的设备,在后面1天是否来访。也就是(ds = T ) 交集 (ds = T+1)
  2. 但是在写代码的时候,我们通常都是逆向的,是找过去第1天的设备,到现在是否来访。 也就是(ds = T-1) 交集 (ds = T)
  3. 比如今天是20231117,底层odps产出的是20231116的分区,但是20231115的次留才能计算
  4. 我们需要一张B表中的一个字段标识是否访问,由上文所说比如 0001 就代表最近4天只有今天来访,0101 就代表最近4天有2天来访问,分别是今天和前天
  5. 比如该用户在20231116 来了,且20231115也来了,那么这个b表在20231115日分区的这个字段的十进制为1 二进制为(01)2;在20231116日分区的这个字段的十进制为3 二进制为(11)2,那么如何计算20231115的留存呢?
  6. 我们将20231116分区这个字段 & (10)2 = pow(2,1) 就能判断该设备是否昨天来访;& (11)2 = pow(2,1)+1就能判断他是否昨天今天都来了
  7. 计算其他留存只是&的字段不同,如果计算当日访问的设备,在第7天是否来访,K1 = (10000001)2 = pow(2,7)+1 ,K2 = (10000000)2 = pow(2,7)

select user_id from B WHERE ds = T and vst_bit_31d & K1 = K1 	-- 当日和7日前来访
交集
select user_id from B WHERE ds = T and vst_bit_31d & K2 = K2	-- 7日前来访
除以
select user_id from B WHERE ds = T and vst_bit_31d & K2 = K2	-- 7日前来访
  1. 如果计算当日访问的设备,在后7天内是否来访,K1 = (11111111)2 = pow(2,8)-1 ,K2 = (10000000)2 = pow(2,7)
select user_id from B WHERE ds = T and vst_bit_31d & K1 > K2 -- 7日前来访 且后面7日中有一天来访就算
交集
select user_id from B WHERE ds = T and vst_bit_31d & K2 = K2
除以
select user_id from B WHERE ds = T and vst_bit_31d & K2 = K2

4. 逻辑

4.1 b表建设

select product_id        -- 业务id
     , visitor_id        -- 访问者id
     , sum(vst_bit_31d)  -- 最近31天的访问bitmap
FROM
(
  -- 昨日分区bit左移1位
  SELECT  product_id
         ,visitor_id
         ,IF(vst_bit_31d > 0, SHIFTLEFT(vst_bit_31d, 1)&2147483647, 0 ) as vst_bit_31d
  FROM   ${your_bitmap_table_name}      -- Bitmap表
  WHERE   ds = '${sub1d}'
  
  UNION ALL
  
  -- 今日访问bit=1
  SELECT   product_id
          ,visitor_id
          ,1 
  FROM    ${your_visit_table_name}     -- 访问表
  WHERE   ds = '${bizdate}'
  group by product_id, visitor_id
) 
GROUP by product_id, visitor_id

4.2 留存计算

需要注意的是product_id 为最细粒度,不可跨粒度计算


@vst_bit_2 :=
SELECT  product_id, count(visitor_id) as uv
FROM    ${your_bitmap_table_name}      -- Bitmap表
WHERE   ds = '${bizdate}'
AND     vst_bit_31d & 2 = 2            -- 昨日访问UV, 分母
AND    ( '${your condition}' )
GROUP BY product_id
;

@vst_bit_3 :=
SELECT  product_id, count(visitor_id) as uv
FROM    ${your_bitmap_table_name}      -- Bitmap表
WHERE   ds = '${bizdate}'
AND     vst_bit_31d & 3 = 3            -- 昨日留存UV, 分子
AND    ( '${your condition}' )
GROUP BY product_id
;

-- 计算次留率
select product_id, min(uv)/max(uv) 次留率
(
select * FROM @vst_bit_3 
UNION ALL
select * FROM @vst_bit_2
)
group by product_id;

4.3 近X天的访问天数

-- 最近7天内的访问天数,其中127=pow(2,7)-1=127
SELECT  product_id
       , visitor_id
       , bi_udf:bi_bit_count(vst_bit_31d&127, 1) AS vst_days
FROM    ${your_bitmap_table_name}      -- Bitmap表
WHERE   ds = '${bizdate}'
AND    ( '${your condition}' )
GROUP BY product_id, visitor_id, bi_udf:bi_bit_count(vst_bit_31d&127, 1)

;

5.分析

● bitmap的使用确实可以加速数据的运算,每天存储的是之前30天是否来访,
● 如果想看过去60天的,也方便进行扩展
○ 可拿ds-30的分区数据,拿到过去30-60天的访问数据
○ 或者把这个vst_bit_31d变成longlong类型
● 但是使用时需要注意,这个建立B表的时候,维度一定要确定不能组合,比较死板
● 新建表后需要按时间顺序回刷

你可能感兴趣的:(数据库,bitmap)