OLAP技術之Kylin官方案例詳細剖析-商業環境實戰
本套系列部落格從真實商業環境抽取案例進行總結和分享,並給出Spark原始碼解讀及商業實戰指導,請持續關注本套部落格。版權宣告:本套Spark原始碼解讀及商業實戰歸作者所有,禁止轉載,歡迎學習。
Kylin官方案例是一個訂單案例,其中包含了訂單事實表,訂單日期表,商品分類維度,賬號維度(購買者和銷售者)以及區域維度(購買者和銷售者)
一:表關係
KYLIN_SALES(事實表) KYLIN_CAL_DT(時間維度)--> KYLIN_SALESKYLIN_SALES.PART_DT = KYLIN_CAL_DT.CAL_DT KYLIN_CATEGORY_GROUPING(商品類別)--> KYLIN_SALES KYLIN_SALES.LEAF_CATEG_ID =KYLIN_CATEGORY_GROUPINGS.LEAF_CATEG_ID KYLIN_SALES.LSTG_SITE_ID = KYLIN_CATEGORY_GROUPINGS.SITE_ID KYLIN_ACCOUNT(購買賬號)--> KYLIN_SALESKYLIN_SALES.BUYER_ID = KYLIN_ACCOUNT.ACCOUNT_ID KYLIN_ACCOUNT(賣出賬號)--> KYLIN_SALESKYLIN_SALES.SELLER_ID = KYLIN_ACCOUNT.ACCOUNT_ID KYLIN_COUNTRY--> KYLIN_ACCOUNT (購買賬號)KYLIN_ACCOUNT.ACCOUNT_COUNTRY = KYLIN_COUNTRY.COUNTRY KYLIN_COUNTRY--> KYLIN_ACCOUNT (賣出賬號)KYLIN_ACCOUNT.ACCOUNT_COUNTRY = KYLIN_COUNTRY.COUNTRY 複製程式碼
二:建立模型
1:Kylin 官方模型 model關係圖如下:

2:模型建設第一步,雪花和星型模型,建立inner join關係,重要的是確定欄位關聯,對於角色維度(KYLIN_ACCOUNT和KYLIN_COUNTRY),需要別名處理。
該處Snapshot Table 總結的很好,所以標明引用地址: ofollow,noindex">juejin.im/post/5bcf37…
對 “Add Lookup Table” 頁面的幾點說明:
- 資料關係不僅僅是事實表與維度表之間(星型模型),維度表和維度表之間(雪花模型)也可以建立聯絡;
- 表與表之間的連線新增有三種:“Left Join”、“Inner Join”、“Right Join”;
- Skip snapshot for this lookup table 選項指的是是否跳過生成 snapshotTable,由於某些 Lookup 表特別大(大於 300M),如果某一個維度的基數比較大 ,可能會導致記憶體出現 OOM,所以在建立 snapshotTable 的時候會限制原始表的大小不能超過配置的一個上限值(kylin.snapshot.max-mb,預設值300);
- 跳過構建 snapshot 的 lookup 表將不能搜尋,同時不支援設定為衍生維度(Derived);
- 大部分情況下都是使用 “Left Join”,其他兩種 Join 方式不是很常用。

3:模型建設第二步,維度選擇:
在 Dimensions 頁面選擇可能參與計算的維度,這裡被選擇的只是在 Cube 構建的時候擁有被選擇資格的維度,並不是最後參與 Cube 構建的維度,推薦將維度表中的欄位都選擇上。 如下展示了Dimensions的選擇:
對於KYLIN_SALES,其中SLR_SEGMENT_CD,PRICE,ITEM_COUNT沒有選擇,所以沒有資格參與cubeId構建

對於KYLIN_CAL_DT,其中僅選擇了部分參與的維度,其他沒有資格參與cubeId構建

對於KYLIN_CATEGORY_GROUPING,其中僅選擇了部分參與的維度,其他沒有資格參與cubeId構建

對於BUYER_ACCOUNT 與 SELLER_ACCOUNT,全部有資格參與cubeId構建

對於BUYER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構建

對於SELLER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構建
同理如上
最終維度選擇結果:

4: Measures度量指標選擇:
在 Measures 頁面選擇可能用於計算的度量。一般而言,銷售額、流量、溫溼度等會作為度量。

5、Settings設定
在 Settings 頁面可以設定分割槽以及過濾條件,其中分割槽是為了系統可以進行增量構建而設計的,目前 Kylin 支援基於日期的分割槽,在 “Partition Date Column” 後面選擇事實表或者維度表中的日期欄位,然後選擇日期格式即可;過濾條件設定後,Kylin 在構建的時候會選擇符合過濾條件的資料進行構建。 需要注意的幾點:
- 時間分割槽列可以支援日期或更細粒度的時間分割槽;
- 時間分割槽列支援的資料型別有 time/date/datetime/integer等;
- 過濾條件不需要寫 WHERE;
- 過濾條件不能包含日期維度。

6、模型總結
該處Snapshot Table 總結的很好,所以標明引用地址: juejin.im/post/5bcf37…
每一個 Snapshot 是和一個 Hive 維度表對應的,生成的過程是:
- 從原始的hive維度表中順序得讀取每一行每一列的值;
- 使用 TrieDictionary 方式對這些所有的值進行編碼(一個值對應一個 Id);
- 再次讀取原始表中每一行的值,將每一列的值使用編碼之後的 Id 進行替換,得到了一個只有 Id 的新表;
- 同時儲存這個新表和 Dictionary 物件(Id 和值的對映關係)就能夠儲存整個維度表;
- Kylin 將這個資料儲存到元資料庫中。
三:建立cube
1:維度剪枝優化
在選擇維度時,每一個維度列可以作為普通維度(Normal),也可以作為衍生維度(Derived)。相對於普通維度來說,衍生維度並不參與維度的 Cuboid,衍生維度對應的外來鍵(FK)參與維度 Cuboid,從而降低 Cuboid 數。在查詢時,對衍生維度的查詢會首先轉換為對外來鍵所在維度的查詢,因此會犧牲少量效能(大部分情況下可以接受)。 1:維度剪枝優化 在一個多維資料集合中,維度的個數決定著維度之間可能的組合數,而每一個維度中成員集合的大小決定著每一個可能的組合的個數,例如有三個普通的維度A、B、C,他們的不同成員數分別為10/100/1000,那麼一個維度的組合有2的3次方個,分別是{空、A、B、C、AB、BC、AC、ABC},每一個成員我們稱為cuboid(維度的組合),而這些集合的成員組合個數分別為1、10、100、1000、10*100、100 1000、10 1000和10 *100 *1000。我們稱每一個dimension中不同成員個數為cardinatily,我們要儘量避免儲存cardinatily比較高的維度的組合。
在上面的例子中我們可以不快取BC和C這兩個cuboid,可以通過計算的方式通過ABC中成員的值計算出BC或者C中某個成員組合的值,這相當於是時間和空間的一個權衡吧。在kylin中存在的四種維度是為了減少cuboid的個數,而不是每一個維度是否快取的,當前kylin是對所有的cuboid中的所有組合都進行計算和儲存的,對於普通的dimension,從上面的例子中可以看出N個維度的cuboid個數為2的N次方,而kylin中設定了一些維度可以減少cuboid個數,當然,這需要使用者對自己需要的維度十分了解,知道自己可能根據什麼進行group by。
1.1、Mandatory維度
這種維度意味著每次查詢的group by中都會攜帶的,將某一個dimension設定為mandatory可以將cuboid的個數減少一半,如下圖:

這是因為我們確定每一次group by都會攜帶A,那麼就可以省去所有不包含A這個維度的cuboid了。
1.2、hierarchy維度
這種維度是最常見的,尤其是在mondrian中,我們對於多維資料的操作經常會有上卷下鑽之類的操作,這也就需要要求維度之間有層級關係,例如國家、省、城市,年、季度、月等。有層級關係的維度也可以大大減少cuboid的個數。如下圖:

這裡僅僅侷限於A/B/C是一個層級,例如A是年份,B是季度、C是月份,那麼查詢的時候可能的組合只有年、xx年的季度、xx年xx季度的xx月,這就意味著我們不能再單獨的對季度和月份進行聚合了,例如我們查詢的時候不能使用group by month,而必須使用group by year,quart,month。如果需要單獨的對month進行聚合,那麼還需要再使用month列定義一個單獨的普通維度。
1.3、derived維度
這類維度的意思是可推導的維度,需要該維度對應的一個或者多個列可以和維度表的主鍵是一對一的,這種維度可以大大減少cuboid個數,如下圖:

例如timeid是時間這個維度表的主鍵,也就是事實表的外來鍵,時間只精確到天,那麼year、month、day三列可以唯一對應著一個time_id,而time_id是事實表的外來鍵,那麼我們可以指定year、month、day為一個derived維度,實際儲存的時候可以只根據timeid的取值決定維度的組合,但這就要求我們在查詢的時候使用的group by必須指定derived維度集合中的所有列。 3.聯合維度(Joint) 每一個聯合維度包括兩個或者更多的維度,聯合維度內的維度,要麼不出現,要麼必須一起出現。不同的聯合之間不應當有共同的維度
1.4. 粒度優化
粒度優化對應的是提高Cube的併發度,其設定是在自定義屬性中的 一共有三個屬性可以提高併發度。 1.kylin.hbase.region.cut(共使用幾個分割槽) 2.kylin.hbase.region.count.min(最少使用幾個分割槽) 3.kylin.hbase.region.count.max(最多使用幾個分割槽)
根據相對應的情況調高最少使用分割槽,降低最大使用分割槽,能夠有效增加系統的並行度。
1.5. RowKey優化
寫的非常好,參考連結: juejin.im/post/5bd5c5…
Kylin 以 Key-Value 的方式將 Cube 儲存到 HBase 中,HBase 的 key,也就是 Rowkey,是由各維度的值拼接而成的;為了更高效地儲存這些值,Kylin 會對它們進行編碼和壓縮;每個維度均可以選擇合適的編碼(Encoding)方式,預設採用的是字典(Dictionary)編碼技術;欄位支援的基本編碼型別如下:
-
dict:適用於大部分欄位,預設推薦使用,但在超高基情況下,可能引起記憶體不足的問題;
-
boolean:適用於欄位值為true, false, TRUE, FALSE, True, False, t, f, T, F, yes, no, YES, NO, Yes, No, y, n, Y, N, 1, 0;
-
integer:適用於欄位值為整數字符,支援的整數區間為[ -2^(8N-1), 2^(8N-1)];
-
date:適用於欄位值為日期字元,支援的格式包括yyyyMMdd、yyyy-MM-dd、yyyy-MM-dd HH:mm:ss、yyyy-MM-dd HH:mm:ss.SSS,其中如果包含時間戳部分會被截斷;
-
time:適用於欄位值為時間戳字元,支援範圍為[ 1970-01-01 00:00:00, 2038/01/19 03:14:07],毫秒部分會被忽略,time編碼適用於 time, datetime, timestamp 等型別;
-
fix_length:適用於超高基場景,將選取欄位的前 N 個位元組作為編碼值,當 N 小於欄位長度,會造成欄位截斷,當 N 較大時,造成 RowKey 過長,查詢效能下降,只適用於 varchar 或 nvarchar 型別;
-
fixed_length_hex:適用於欄位值為十六進位制字元,比如 1A2BFF 或者 FF00FF,每兩個字元需要一個位元組,只適用於 varchar 或 nvarchar 型別。
-
和Hbase 的RowKey優化類似,在查詢的過程中,被用作過濾條件的維度可能放在其他維度的前面,經常出現的維度應該放在前面,基數比較大的維度應該放在前面