數倉建模-用戶維表的構建(一)-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

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