Cube和Kylin創建Cube的過程

轉載:http://www.aboutyun.com/thread-20757-1-1.html

簡介

  Kylin作爲一個OLAP引擎,需要Cube模型支撐,在我們的工作過程中,在和用戶以及相關的開發人員、測試、產品等介紹Kylin的過程中,他們總是會對Cube的模型有一些疑惑,作爲經常接觸這個概念的我來說這是再明瞭不過的了,而他們還是會在我講解多次之後表示還在雲裏霧裏,所以就希望通過一篇關於Cube和Kylin創建Cube的過程來聊一下Cube是什麼,以及Kylin的一些高級設置。

Cube

  一個Cube(多維立方體)其實就是一個多維數組,例如定義一個三維數組int array[M][N][K],每一個維度分別有M、N和K個成員,同樣對於一個Cube而言,也可以有三個維度,假設分別爲time、location和product,每一個維度的distinct值(稱爲維度的cardinality)分別是M、N和K個,而數組中的每一個值則是每一個維度取一個值對應的聚合結果,例如array[0][1][2],它就相當於time取第一個值(假設爲2016-01-01),location取第二個值(假設爲HangZhou)、product取第三個值(假設爲Food)對應的一個聚合結果,假設這裏的聚合函數爲COUNT(1),那麼求得的值相當於執行了SELECT COUNT(1) from table where time = ‘2016-01-01’ and location = ‘HangZhou’ and product = ‘Food’,這樣當我們有多個聚合函數呢,那麼就相當於數組中的每一個元素是一個包含多個值的結構體:

struct{

int count;          //保存COUNT(1)的值

double sales;    //保存SUM(sales)的值

double cost;     //保存SUM(cost)的值

}

 

 如上圖,每一個data cell就保存了一個類似的結構體,因此只要能夠計算和保存這樣的一個多維數組,我們所有的查詢就都可以直接定位到多維數組中的一個或者一批值,然後進行過濾得到結果。 
  但是一個多維數組和Cube模型還是有一些區別,例如在多維數組中我們必須在每一維指定一個值(下標)才能對應得到一個確定的值,但是在Cube中,雖然定義了三個維度,但是我可以只指定兩個維度,甚至一個維度都不指定而進行查詢,例如執行SELECT COUNT(1) from table where time = ‘2016-01-01’ and location = ‘HangZhou’,這就相當於求數組中array[0][1]的值,但這個返回的是一個數組,而SQL返回的是一個值,因此需要將這個數組中的每一個data cell取出來再進行聚合運算(例如計數、相加等)得到的值纔是真正的結果。 
  好了,到這裏可以看出有兩種方案計算上面的SQL:1、取出array[0][1]這個數組再進行聚合,2、直接計算出來這個二維數組,那麼在這個二維數組上指定time和location就能夠對應一個data cell值了。由於可以通過方案1進行再聚合計算,所以理論上如果保存了所有維度的組合(假設N個維度,那麼就是一個N爲的數組),那麼所有的N-1、N-2、…、0維的任何值都是可以通過這個N維數組進行再聚合計算出來的,但是這勢必就影響查詢的性能。所以這其實就是時間和空間的一個博弈,那麼在實踐中到底應該如何進行權衡呢,答案是:看需求!也就是建立哪些數組(N個維度,第K層有C(N,K)個K維數組)就要看你真正要執行的查詢有哪些了,對經常在一塊進行組合查詢的維度簡歷一個數組是再適合不過的了,例如time和location這兩個維度老是在一個SQL中出現,那麼建立一個這樣的二維數組是需要的,而product和location這兩個不會在一個SQL中出現,那麼這個二維數組就不需要預計算了。那麼在Kylin裏面是如何決定預計算哪些數組呢?

創建Cube

  這裏的一切就要從Kylin創建Cube開始說起,在Kylin中創建一個Cube需要以下幾步: 
1、設置Cube名、描述信息等 
2、設置Cube依賴的表模型(星狀模型,一個事實表和可選的多個維度表) 
3、設置維度(維度有幾種類型這裏不再討論,創建完之後就可以暫時性的忽略這幾種不同的類型,都把它當做普通的維度就可以了) 
4、設置度量(每一個度量包括列和聚合函數,列只能是事實表上的列) 
5、設置filter條件(用於對錶中的數據進行過濾) 
6、設置增量更新的信息(設置增量列和起始時間,該列必須是時間格式列) 
7、高級設置(設置維度組、RowKey等)

高級設置

  前面6步的設置比較淺顯易懂,那麼對於Cube的優化主要通過“高級設置”這一步實現的,這裏設置的主要有以下幾種: 
1、設置Rowkey 
2、設置維度組 
3、設置Cube Size 
  在進入到設置RowKey的時候會看到每一個維度的設置(Derived維度看到的是外鍵列而不是Derived的列),每一個維度可以設置ID(通過拖拽可以改變每一個維度的ID)、Mandatory、Dictionary和Length。

Mandatory維度

  首先看一下Mandatory維度,需要設置爲Mandatory的維度是哪些在大多數SQL中都會出現的維度,例如time這個維度,如果每次查詢都需要帶上它進行過濾或者group by,那麼就可以把它設置爲mandatory。

維度順序

  其次,ID決定了這個維度在數組中執行查找時該維度對應的第一個維度,例如在上例中time的ID就是1,location對應的ID就是2,product對應的ID爲3,這個順序是非常重要的,一般情況我們會將mandatory維度放置在rowkey的最前面,而其它的維度需要將經常出現在過濾條件中的維度放置在靠前的位置,假設在上例的三維數組中,我們經常使用time進行過濾,但是我把time的ID設置爲3(location的ID=1,product的ID=2),這時候如果從數組中查找time大於’2016-01-01’並且小於’2016-01-31’,這樣的查詢就需要從這樣的最小的key=<min(location)、min(product)、‘2016-01-01’>掃描到最大的key=<max(location)、max(product)、‘2016-01-31’>,但是如果把time的ID設置爲1,掃描的區間就會變成key=<‘2016-01-01’、min(location)、min(product)>到key=<‘2016-01-31’、max(location)、max(product)>,Kylin在實現時需要將Cube的數組存儲在Hbase中,然後按照hbase中的rowkey進行掃描,假設min(location)=’BeiJing’、max(location)=’ZhengZhou’, min(product)=’aaaa’,max(product)=’zzzz’,這樣在第一種情況下hbase中需要掃描的rowkey範圍是[BeiJing-aaaa-2016-01-01, ZhengZhou-zzzz-2016-01-31],而第二種情況需要掃描的rowkey範圍是[2016-01-01-BeiJing-aaaa, 2016-01-31-ZhengZhou-zzzz].可以看出第二種情況可以減少掃面的rowkey,查詢的性能也就更好了。但是在kylin中並不會存儲原始的成員值(例如HangZhou、2016-01-01這樣的值),而是需要對它們進行編碼,是否需要編碼則有後面兩個設置項決定。

維度字典

  Dictionary可以設置爲true和false,設置爲true表示需要爲這個維度建立字典樹,如果設置爲false則表示不需要設置,而需要設置Length,而Length則意味着在實際存儲到hbase的rowkey時使用該維度的前Length個字符作爲它的值(剪切每一個成員值只保留前Length個字符),一般情況下是不建議設置Length的,而是設置Dcitionary爲true,只有當cardinality比較大時並且只需要取前N個字節就可以表示這個維度時才建議設置Length=N,因爲每一個維度的dictionary都會保存在內存中,如果字典樹佔用很大的內存會影響kylin的使用甚至導致OOM,對於dictionary的編碼使用的是字典樹,它的原理實際上是爲每一個維度成員賦予一個整數的id,實際存儲的時候存儲的是這個id的二進制值(使用int最多佔用4個字節),並且保證每一個id的順序和維度成員的順序相同的,例如aaa的id=1,aab的id=2,aac的id=3,這樣在查詢的時候就可以直接根據column>aaa轉換成id>1,方便hbase coprocessor的處理。

維度組

  設置完了RowKey接下來要設置維度組,維度組的設置主要是爲了讓不出現在一個查詢中的兩個維度不計算cuboid(通過劃分到兩個不同的維度組中),這其實相當於把一個cube的樹結構劃分成多個不同的樹,可以在不降低查詢性能的情況下減少cuboid的計算量,目前在Kylin-1.x版本中cuboid的算法有一點的問題,可以參考我對這個算法的改進那篇博文。

Cube Size

  最後設置CubeSize,該項的設置會對cuboid轉換成hfile這一步的計算產生影響,並且影響hbase中表的分區大小,可選值爲SMALL、MEDIUM和LARGE,在kylin-1.1版本之後可以在配置文件可以設置這三個配置的分區大小,默認情況下SMALL=10GB,MEDIUM=20GB,LARGE=100GB,在計算完全部的cuboid之後會統計所有cuboid文件中key和value的大小,然後根據這個大小和用戶的CubeSize配置決定劃分多少region,然後執行一個MR任務計算每一個region的hfile,由於kylin在創建hfile的時候都是通過預分區的方式(通過計算出每一個分區臨界值的key),然後批量load到htable的,所以不會導致region的分裂和合並,所以我們還是建議將CubeSize設置爲SMALL,並且配置中將small的配置設置爲5GB,這樣可以提高生成hfile這一步的速度(每一個region負責一個region,減小分區的大小會增加reducer的個數)。

總結

  好了,本文主要介紹了kylin中創建cube的過程,其中還主要介紹了cube模型的概念,最後詳細介紹了kylin在創建cube中的高級設置的優化方案,如果有什麼錯誤的地方,還希望多多指正。

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