更新时间:2024-09-02 GMT+08:00

使用场景

背景

目前在互联网、教育、游戏等行业都有实时精准营销的需求。通过系统生成用户画像,在营销时通过条件组合筛选用户,快速提取目标群体。例如:

  • 在电商行业中,商家在进行营销活动前,需要根据活动的目的,圈选一批满足特定特征的目标用户群体进行广告推送。
  • 在教育行业中,需要根据学生不同的特征,推送有针对性的练习题目,帮助学生查漏补缺。
  • 在搜索、视频、门户网站中,根据用户关注的热点,推送不同的内容。

这些业务场景都有一些共同的特点:

  • 数据量庞大,运算量极大。
  • 用户规模庞大,标签多,字段多,占用存储空间也多。
  • 圈选的特征条件多样化,很难找到固定索引,如果每个字段一个索引,存储空间又会暴增。
  • 性能要求高,因为实时营销要求秒级响应。
  • 数据更新时效要求高,用户画像几乎要求实时更新。

针对上述业务场景特点,GaussDB(DWS)的roaringbitmap可以高效生成、压缩、解析位图数据,支持最常见的位图聚合操作(与、或、非、异或),满足用户在亿级以上、千万级标签的大数据量下实时精准营销、快速圈选用户的需求。

roaringbitmap使用示例

假设有一张用户浏览网页的流水信息表userinfo,表中的字段如下:

1
2
3
4
5
6
7
CREATE TABLE userinfo
(userid int,
age int,
gender text,
salary int,
hobby  text
)WITH (orientation=column);

userinfo表中的数据会随着用户信息的变化不断增长,比如用户有多个hobby属性,那么就有多条记录。

如果用户需要筛选出所有“收入大于10000元的男性,年龄大于30岁,爱好钓鱼”的群体,向这些目标群体推送特定的消息。

传统的方法是直接在原表上执行查询,语句如下:

1
SELECT distinct userid FROM userinfo WHERE salary > 10000 AND age > 30 AND gender ='m' AND hobby ='fishing';

当userinfo表的数据量不大的时候,可以通过在salary,age,gender,hobby列上建立索引来满足需求。但是如果userinfo表的数据量非常大,同时一张表的标签数非常多的时候,上述语句就不能满足诉求,因为如下原因:

  • 需要创建的索引会非常多。
  • count (distinct)的性能比较差。

这种场景下使用roaringbitmap就会有比较好的效果。

  1. 新建一张Roaringbitmap表:
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE userinfoset
    ( age int,
    gender text,
    salary int,
    hobby  text,
    userset roaringbitmap,
    PRIMARY KEY(age,gender,salary,hobby)
    )WITH (orientation=column);
    
  2. 所有userinfo表中的数据要通过标签列聚合到userinfoset表中。可以采用对全量数据进行聚合的方法(如下命令所示)。也可以采用只对增量数据进行聚合的方法。只对增量数据进行聚合即对含有相同的标签的用户集合放到表的一条记录中,通常可以通过upsert来实现。考虑到其中频繁的update操作可能产生大量的脏数据,因此对增量数据进行聚合的方法,建议将userinfoset表创建为行存表。
    1
    2
    3
    4
    5
    INSERT INTO userinfoset
    SELECT age, gender, salary, hobby, rb_build_agg(userid)
    FROM 
    userinfo
    GROUP BY age, gender, salary, hobby;
    
  3. 直接查询userinfoset表获得用户筛选信息。
    1
    SELECT rb_iterate(rb_or_agg(userset)) FROM userinfoset WHERE salary > 10000 AND age > 30 AND gender ='m' AND hobby ='fishing';
    

数据进行聚合后的userinfoset的数据量相比源表小了很多,基表scan的性能会快很多,同时基于Roaringbitmap的优势,计算rb_or_agg和rb_iterate的性能也很好,相比传统的方法,性能明显提升。