数仓建模-用户维表的构建(一)-map join和smb join

背景简介

在绝大部分场景中,用户维度都是一个必不可少的维度,而且随着业务发展和积累,相比其他维度,用户维度应该会是一数据量个比较大的维度。

由于历史原因,在我们这,用户维度的数据源来自于几个业务库,每个业务库记录了每个用户不同的信息。比如现在有两个业务A和B分别记录了各自业务系统里获取的用户信息,其中业务A产出的用户信息表userinfoA如下。这里的userid跟注册无关,而跟手机有关,这意味着一个手机上,如果出现我们app多个产品线,比如主版本,预装定制版,厂商定制版等等,虽然会是对应不同的app,但是userid是一样的,在后台会有一个产品id的字段加以区分。这里userinfo表记录的是跟产品无关的信息,比如系统平台(安卓,ios),系统版本等等。

                                             userinfoA
userid 用户id
infoA1 信息1,与产品无关的信息,如手机型号,平台版本等
ctime 记录创建时间
mtime 记录修改时间

业务B产出的用户信息表userinfoB如下,其中pid即之前说的产品id,用以区分不同产品。

                                         userinfoB
userid 用户id
pid 产品id
infoB 信息B,与产品有关的信息,如用户在某产品的激活时间等
ctime 记录创建时间
mtime 记录修改时间

两个表都是在业务上都进行了分表操作,数据量大约都在8亿条左右。当构建用户维表时,一种思路是为每个产品pid,创建一份维表,另一种是维护一个维表,加入产品id作为其中一列。考虑到实际场景,一方面产品id和用户id作为日志要求的必须字段,存在于绝大部分有效日志中,另一方面,主线产品其实占了绝大部分记录数,其余产品线多且杂,统计需求上也基本以主线产品为主。所以采用了第二种方式,这样在有必要的情况下,也能抽取特定的pid生成特定产品的用户维表。所以初步维表设计如下

                                                                                                   dim_userinfo
userid
pid
infoA
infoB

原始数据userinfoA和userinfoB可以通过DataX或者sqoop每天定时导入的hive中,生成ods_userinfoA和ods_userinfoB。

 

实现思路

1、直接join

简单来说,其实这个维表的生成,可以通过一个简单的join操作来完成,确实最开始也就这么干的。但因为是大表join大表,所以执行耗时较长。

2、map-join

原理介绍网上可以搜到很多,在这因为两个表都很大,所以不太适用map-join来优化。在这注意的一点是,下列情况,即使其中一个表是小表,也不能走map-join,具体情况如下,是用explain 实测的结果,m表示map-join,mr表示普通map-reduce。

  full join left join  right join  join
小表在前 mr mr m m
小表在后 mr m mr m

 

其实简单思考下, 小表是要放在内存中所以才能提高效率,大表需要分配到不同的节点上去,所以小表必须是从表,比如left join的右表或者right join的左表。wiki原文是这样说的

Outer joins offer more challenges. Since a map-join operator can only stream one table, the streamed table needs to be the one from which all of the rows are required. For the left outer join, this is the table on the left side of the join; for the right outer join, the table on the right side, etc. This means that even though an inner join can be converted to a map-join, an outer join cannot be converted. An outer join can only be converted if the table(s) apart from the one that needs to be streamed can be fit in the size configuration. A full outer join cannot be converted to a map-join at all since both tables need to be streamed.

3、smb-join

原理和介绍,也不多说了。在使用smb-join之前,对该技术本身没有啥说的,只是测试了下,现有环境下分桶数量配置多少合适。最开始,想当然得以为分桶后每个桶数据大小也不能超过map-join里默认设定的25MB的限制,所以分桶设置的很多,结果导致执行起来,整体耗时很长。另一方面,分桶数量越小,在往分桶表里插入数据时,通过mr上的log发现插入时间好像会越长,因此一个合适的分桶数是关键,目前还没找到官方准则来指导,所以还是靠实测来设定。除此之外,还有就是mr上的空间占用,分桶表会比普通表占用更多的存储空间。公司集群测试结果如下

  普通join 分桶64 分桶100 分桶256 分桶500 分桶1000
map 725 64 100 256 500 1000
reduce 34 0 0 0 0 0
time 8min 1min34 33s 2min24 3min28 4min
空间 33g join 20g 基本一致,都在100g join 90g左右

 

除了第一次开始设置了100000分桶,跑跪了之后,直接测试的100,发现结果挺好的,所以依次对比了其他几个分桶数。空间上没仔细比对,其实所占空间跟分桶数没有线性关系,基本一致。

开启smb-join需要配置

set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

为了保证插入分桶表的实际分桶数与设定一致,或者手动指定reducer数量与分桶一致,如果不一致会导致smb-join报错。

set hive.enforce.bucketing=true;
set hive.enforce.sorting=true;

而且分桶可以根据多列,比如实际场景中,类似ods_userinfoB这样,以userid和pid为联合主键的业务表有好几个,所以可以在分桶表定义如下,指定两列userid和pid作为分桶的列。

   CREATE TABLE `xxx.ods_userinfoB`(       
   `userid` string,                              
   `pid` string,                                                              
   `infoB` string)    
   
clustered by (userid,pid) sorted by (userid,pid) into 100 buckets
   
 ROW FORMAT SERDE                                   
   'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'  
 STORED AS INPUTFORMAT                              
   'org.apache.hadoop.mapred.TextInputFormat'       
 OUTPUTFORMAT                                       
   'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' 
 LOCATION                                           
   'hdfs://xxxxxxxxxxxxxxx/ods_userinfoB' ;

最后执行join操作时,通过explain命令可以看出

说明成功使用了smb-join

后记

文中测试数据仅测试了两个大表的join,实际业务中,其实是需要很多个大表连续join的,所以整体执行效率会优化很多。下篇文章,介绍下如何根据用户维表,构建拉链表,用来存储长期数据,因为现在其实每天存储的都是T-1的全量,方便但是无法追溯历史。

参考资料

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+JoinOptimization

https://blog.csdn.net/weixin_44033089/article/details/88422273

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章