不多說,直接上干貨!
1、 Cube的物理模型

如上圖所示,一個常用的3維立方體,包含:時間、地點、產品。假如data cell 中存放的是產量,則我們可以根據時間、地點、產品來確定產量,同時也可以根據時間、地點來確定所有產品的總產量等。
Apache Kylin就將所有(時間、地點、產品)的各種組合實現算出來,data cell 中存放度量,其中每一種組合都稱為cuboid。估n維的數據最多有2^n個cuboid,不過Kylin通過設定維度的種類,可以減少cuboid的數目。
2 、Cube構建算法介紹
2.1 逐層算法(Layer Cubing)
我們知道,一個N維的Cube,是由1個N維子立方體、N個(N-1)維子立方體、N*(N-1)/2個(N-2)維子立方體、......、N個1維子立方體和1個0維子立方體構成,總共有2^N個子立方體組成,在逐層算法中,按維度數逐層減少來計算,每個層級的計算(除了第一層,它是從原始數據聚合而來),是基於它上一層級的結果來計算的。
比如,[Group by A, B]的結果,可以基於[Group by A, B, C]的結果,通過去掉C后聚合得來的;這樣可以減少重復計算;當 0維度Cuboid計算出來的時候,整個Cube的計算也就完成了。

如上圖所示,展示了一個4維的Cube構建過程。
此算法的Mapper和Reducer都比較簡單。Mapper以上一層Cuboid的結果(Key-Value對)作為輸入。由於Key是由各維度值拼接在一起,從其中找出要聚合的維度,去掉它的值成新的Key,並對Value進行操作,然后把新Key和Value輸出,進而Hadoop MapReduce對所有新Key進行排序、洗牌(shuffle)、再送到Reducer處;Reducer的輸入會是一組有相同Key的Value集合,對這些Value做聚合計算,再結合Key輸出就完成了一輪計算。
每一輪的計算都是一個MapReduce任務,且串行執行; 一個N維的Cube,至少需要N次MapReduce Job。
算法優點
- 此算法充分利用了MapReduce的能力,處理了中間復雜的排序和洗牌工作,故而算法代碼清晰簡單,易於維護;
- 受益於Hadoop的日趨成熟,此算法對集群要求低,運行穩定;在內部維護Kylin的過程中,很少遇到在這幾步出錯的情況;即便是在Hadoop集群比較繁忙的時候,任務也能完成。
算法缺點
- 當Cube有比較多維度的時候,所需要的MapReduce任務也相應增加;由於Hadoop的任務調度需要耗費額外資源,特別是集群較龐大的時候,反復遞交任務造成的額外開銷會相當可觀;
- 由於Mapper不做預聚合,此算法會對Hadoop MapReduce輸出較多數據; 雖然已經使用了Combiner來減少從Mapper端到Reducer端的數據傳輸,所有數據依然需要通過Hadoop MapReduce來排序和組合才能被聚合,無形之中增加了集群的壓力;
- 對HDFS的讀寫操作較多:由於每一層計算的輸出會用做下一層計算的輸入,這些Key-Value需要寫到HDFS上;當所有計算都完成后,Kylin還需要額外的一輪任務將這些文件轉成HBase的HFile格式,以導入到HBase中去;
- 總體而言,該算法的效率較低,尤其是當Cube維度數較大的時候;時常有用戶問,是否能改進Cube算法,縮短時間。
2 .2 快速Cube算法(Fast Cubing)
快速Cube算法(Fast Cubing)是麒麟團隊對新算法的一個統稱,它還被稱作“逐段”(By Segment) 或“逐塊”(By Split) 算法。
該算法的主要思想是,對Mapper所分配的數據塊,將它計算成一個完整的小Cube 段(包含所有Cuboid);每個Mapper將計算完的Cube段輸出給Reducer做合並,生成大Cube,也就是最終結果;圖2解釋了此流程。

與舊算法相比,快速算法主要有兩點不同
- Mapper會利用內存做預聚合,算出所有組合;Mapper輸出的每個Key都是不同的,這樣會減少輸出到Hadoop MapReduce的數據量,Combiner也不再需要;
- 一輪MapReduce便會完成所有層次的計算,減少Hadoop任務的調配。
子立方體生成樹的遍歷
值得一提的還有一個改動,就是子立方體生成樹(Cuboid Spanning Tree)的遍歷次序;在舊算法中,Kylin按照層級,也就是廣度優先遍歷(Broad First Search)的次序計算出各個Cuboid;在快速Cube算法中,Mapper會按深度優先遍歷(Depth First Search)來計算各個Cuboid。深度優先遍歷是一個遞歸方法,將父Cuboid壓棧以計算子Cuboid,直到沒有子Cuboid需要計算時才出棧並輸出給Hadoop;最多需要暫存N個Cuboid,N是Cube維度數。
采用DFS,是為了兼顧CPU和內存:
- 從父Cuboid計算子Cuboid,避免重復計算;
- 只壓棧當前計算的Cuboid的父Cuboid,減少內存占用。

-
-
-
-
-
-
-
-
立方體生成數的遍歷過程
-
-
-
-
-
-
-
上圖是一個四維Cube的完整生成樹;按照DFS的次序,在0維Cuboid 輸出前的計算次序是 ABCD -> BCD -> CD -> D -> , ABCD, BCD, CD和D需要被暫存;在被輸出后,D可被輸出,內存得到釋放;在C被計算並輸出后,CD就可以被輸出; ABCD最后被輸出。
4.3 、Cube構建流程

主要步驟如下:
- 構建一個中間平表(Hive Table):將Model中的fact表和look up表構建成一個大的Flat Hive Table。
- 重新分配Flat Hive Tables。
- 從事實表中抽取維度的Distinct值。
- 對所有維度表進行壓縮編碼,生成維度字典。
- 計算和統計所有的維度組合,並保存,其中,每一種維度組合,稱為一個Cuboid。
- 創建HTable。
- 構建最基礎的Cuboid數據。
- 利用算法構建N維到0維的Cuboid數據。
- 構建Cube。
- 將Cuboid數據轉換成HFile。
- 將HFile直接加載到HBase Table中。
- 更新Cube信息。
- 清理Hive。