Kylin官方案例詳細剖析及剪枝優化-OLAP商業環境實戰

版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。版權聲明:禁止轉載,歡迎學習。算法

Kylin官方案例是一個很是經典的案例,包含的技術細節經過深挖能呈現出更具價值的信息,如:數據倉庫理論,星型模型,雪花模型,角色扮演維度,維度剪枝等。相信您會經過個人深刻剖析,有一種恍然大悟的感受。官方案例是一個訂單案例,其中包含了訂單事實表,訂單日期表,商品分類維度,帳號維度(購買者和銷售者)以及區域維度(購買者和銷售者)。數據庫

一 Kylin官方案例表關係及字段詳解

1.1 Kylin官方案例表簡要說明

  • KYLIN_SALES是事實表,保存了銷售訂單的明細信息。各列分別保存着賣家、商品分類、訂單金額、商品數量等信息,每一行對應着一筆交易訂單。
  • KYLIN_CATEGORY_GROUPINGS是維表,保存了商品分類的詳細介紹,例如商品分類名稱等。
  • KYLIN_CAL_DT也是維表,保存了時間的擴展信息。如單個日期所、月始、周始、年份、月份等。
  • KYLIN_ACCOUNT也是維表,做爲角色扮演維度,包含購買者和開發者帳號。
  • KYLIN_COUNTRY包含區域維度,做爲角色扮演維度,包含購買者和開發者所在區域信息。

1.2 KYLIN_SALES 事實表字段詳解:

1.3 KYLIN_CATEGORY_GROUPINGS 字段說明 :

1.3.1 KYLIN_CATEGORY_GROUPINGS主要字段:

  • LEAF_CATEG_ID:主鍵
  • SITE_ID:外鍵

1.3.2 KYLIN_CATEGORY_GROUPINGS 對外鏈接關係:

1.3.3 KYLIN_CATEGORY_GROUPINGS 主要字段解釋:

1.4 KYLIN_COUNTRY 主要字段詳解:

1.5 KYLIN_ACCOUNT 主要字段詳解:

1.6 雪花模型關係總覽:

二 創建模型(Model)

2.1 Kylin 官方模型 model關係圖以下:

2.2 第一步:雪花和星型模型,創建inner join關係,重要的是肯定字段關聯,對於角色維度(KYLIN_ACCOUNT和KYLIN_COUNTRY),須要別名處理。

對 「Add Lookup Table」 頁面的幾點說明:緩存

  1. 數據關係不只僅是事實表與維度表之間(星型模型),維度表和維度表之間(雪花模型)也能夠創建聯繫;
  2. 表與表之間的鏈接添加有三種:「Left Join」、「Inner Join」、「Right Join」;
  3. Skip snapshot for this lookup table 選項指的是是否跳過生成 snapshotTable,因爲某些 Lookup 表特別大(大於 300M),若是某一個維度的基數比較大 ,可能會致使內存出現 OOM,因此在建立 snapshotTable 的時候會限制原始表的大小不能超過配置的一個上限值(kylin.snapshot.max-mb,默認值300);
  4. 跳過構建 snapshot 的 lookup 表將不能搜索,同時不支持設置爲衍生維度(Derived);
  5. 大部分狀況下都是使用 「Left Join」,其餘兩種 Join 方式不是很經常使用。

2.2.1 每個 Snapshot 是和一個 Hive 維度表對應的,生成的過程是:

  • 從原始的hive維度表中順序得讀取每一行每一列的值;架構

  • 使用 TrieDictionary 方式對這些全部的值進行編碼(一個值對應一個 Id);併發

  • 再次讀取原始表中每一行的值,將每一列的值使用編碼以後的 Id 進行替換,獲得了一個只有 Id 的新表;高併發

  • 同時保存這個新表和 Dictionary 對象(Id 和值的映射關係)就可以保存整個維度表;post

  • Kylin 將這個數據存儲到元數據庫中。性能

    該處Snapshot Table 總結的很好,因此標明引用地址:https://juejin.im/post/5bcf370d6fb9a05cff3255dd
    複製代碼

2.2.2 雪花模型關係圖

2.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構建

同理如上

2.3.1 資格維度選擇結果總覽:

2.4 第三步: Measures 度量指標選擇:

在 Measures 頁面選擇可能用於計算的度量。通常而言,銷售額、流量、溫溼度等會做爲度量。

2.5 第四步:Settings設置

在 Settings 頁面能夠設置分區以及過濾條件,其中分區是爲了系統能夠進行增量構建而設計的,目前 Kylin 支持基於日期的分區,在 「Partition Date Column」 後面選擇事實表或者維度表中的日期字段,而後選擇日期格式便可;過濾條件設置後,Kylin 在構建的時候會選擇符合過濾條件的數據進行構建。 須要注意的幾點:

  1. 時間分區列能夠支持日期或更細粒度的時間分區;
  2. 時間分區列支持的數據類型有 time/date/datetime/integer等;
  3. 過濾條件不須要寫 WHERE;
  4. 過濾條件不能包含日期維度。

三 構建cube模型

3.1 維度選擇知識總結

在選擇維度時,每個維度列能夠做爲普通維度(Normal),也能夠做爲衍生維度(Derived)。相對於普通維度來講,衍生維度並不參與維度的 Cuboid,衍生維度對應的外鍵(FK)參與維度 Cuboid,從而下降 Cuboid 數。在查詢時,對衍生維度的查詢會首先轉換爲對外鍵所在維度的查詢,所以會犧牲少許性能(大部分狀況下能夠接受)。

3.1.1 維度剪枝優化

如何進行維度優化,首先請確認你設置的cube維度都是你查詢時會使用到的。

目前Kylin可使用的維度優化手段有如下幾種:

  • 彙集組
  • 衍生緯度
  • 強制維度
  • 層次維度
  • 聯合維度
  • Extended Column

在一個多維數據集合中,維度的個數決定着維度之間可能的組合數,而每個維度中成員集合的大小決定着每個可能的組合的個數,例若有三個普通的維度A、B、C,他們的不一樣成員數分別爲10/100/1000,那麼一個維度的組合有2的3次方個,分別是{空、A、B、C、AB、BC、AC、ABC},每個成員咱們稱爲cuboid(維度的組合),而這些集合的成員組合個數分別爲一、十、100、1000、10*100、100 1000、101000和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。

3.1.2 Mandatory維度

這種維度意味着每次查詢的group by中都會攜帶的,將某一個dimension設置爲mandatory能夠將cuboid的個數減小一半,以下圖:

這是由於咱們肯定每一次group by都會攜帶A,那麼就能夠省去全部不包含A這個維度的cuboid了。

3.1.3 hierarchy維度

這種維度是最多見的,尤爲是在mondrian中,咱們對於多維數據的操做常常會有上卷下鑽之類的操做,這也就須要要求維度之間有層級關係,例如國家、省、城市,年、季度、月等。有層級關係的維度也能夠大大減小cuboid的個數。以下圖:

這裏僅僅侷限於A/B/C是一個層級,例如A是年份,B是季度、C是月份,那麼查詢的時候可能的組合只有年、xx年的季度、xx年xx季度的xx月,這就意味着咱們不能再單獨的對季度和月份進行聚合了,例如咱們查詢的時候不能使用group by month,而必須使用group by year,quart,month。若是須要單獨的對month進行聚合,那麼還須要再使用month列定義一個單獨的普通維度。

3.1.4 derived維度

這類維度的意思是可推導的維度,須要該維度對應的一個或者多個列能夠和維度表的主鍵是一對一的,這種維度能夠大大減小cuboid個數,以下圖:

例如timeid是時間這個維度表的主鍵,也就是事實表的外鍵,時間只精確到天,那麼year、month、day三列能夠惟一對應着一個time_id,而time_id是事實表的外鍵,那麼咱們能夠指定year、month、day爲一個derived維度,實際存儲的時候能夠只根據timeid的取值決定維度的組合,但這就要求咱們在查詢的時候使用的group by必須指定derived維度集合中的全部列。 3.聯合維度(Joint) 每個聯合維度包括兩個或者更多的維度,聯合維度內的維度,要麼不出現,要麼必須一塊兒出現。不一樣的聯合之間不該當有共同的維度

3.1.5 聯合維度

聯合維度:將幾個維度視爲一個維度。 適用場景:

  • 1 能夠將肯定在查詢時必定會同時使用的幾個維度設爲一個聯合維度。

  • 2 能夠將基數很小的幾個維度設爲一個聯合維度。

  • 3 能夠將查詢時不多使用的幾個維度設爲一個聯合維度。

優化效果:將N個維度設置爲聯合維度,則這N個維度組合成的cuboid個數會從2的N次方減小到1。

應用實例:

假設建立一個交易數據的Cube,它具備不少普通的維度,像是交易日期 cal_dt,交易的城市 city,顧客性別 sex_id 和支付類型 pay_type 等。分析師經常使用的分析方法爲經過按照交易時間、交易地點和顧客性別來聚合,獲取不一樣城市男女顧客間不一樣的消費偏好,例如同時聚合交易日期 cal_dt、交易的城市 city 和顧客性別 sex_id來分組。 聚合組:[cal_dt, city, sex_id,pay_type] 聯合維度: [cal_dt, city, sex_id]

Case 1:
SELECT cal_dt, city, sex_id, count(*) FROM table GROUP BY cal_dt, city, sex_id 
則它將從Cuboid [cal_dt, city, sex_id]中獲取數據
複製代碼
Case2:

若是有一條不經常使用的查詢:

SELECT cal_dt, city, count(*) FROM table GROUP BY cal_dt, city
 則沒有現成的徹底匹配的 Cuboid,Apache Kylin 會經過在線計算的方式,從現有的 Cuboid 中計算出最終結果。
複製代碼

3.1.6 粒度優化

粒度優化對應的是提升Cube的併發度,其設置是在自定義屬性中的 一共有三個屬性能夠提升併發度。 1.kylin.hbase.region.cut(共使用幾個分區) 2.kylin.hbase.region.count.min(最少使用幾個分區) 3.kylin.hbase.region.count.max(最多使用幾個分區)

根據相對應的狀況調高最少使用分區,下降最大使用分區,可以有效增長系統的並行度。

3.1.7 RowKey優化

Rowkeys: 是由維度編碼值組成。」Dictionary」 (字典)是默認的編碼方式; 字典只能處理中低基數(少於一千萬)的維度;若是維度基數很高(如大於1千萬), 選擇 「false」 而後爲維度輸入合適的長度,一般是那列的最大長度值; 若是超過最大值,會被截斷。請注意,若是沒有字典編碼,cube 的大小可能會很是大。 你能夠拖拽維度列去調整其在 rowkey 中位置; 位於rowkey前面的列,將能夠用來大幅縮小查詢的範圍。一般建議將 mandantory 維度放在開頭, 而後是在過濾 ( where 條件)中起到很大做用的維度;若是多個列都會被用於過濾,將高基數的維度(如 user_id)放在低基數的維度(如 age)的前面。

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優化相似,在查詢的過程當中,被用做過濾條件的維度可能放在其餘維度的前面,常常出現的維度應該放在前面,基數比較大的維度應該放在前面

    (參考連接:https://juejin.im/post/5bd5c59851882565e031f4be)
    複製代碼

3.2:官方案例維度選擇

3.2.1 KYLIN_SALES維度選擇遇到的問題

發現鏈接鍵沒有勾選,如:LEAF_CATEG_ID 和LSTG_SITE_ID是外鍵,PART_DT 的是衍生外鍵也沒有選擇,所以,意味着在CUBE構建時,只用關心計算維度,鏈接鍵雖然不選擇,衍生維度仍是生效的:

3.2.2 KYLIN_CAL_DT 維度選擇,發現PART_DT 的是衍生主鍵沒有勾選:

3.2.3 KYLIN_CATEGORY_GROUPINGS維度選擇遇到的問題

維度選擇,發現鏈接鍵LEAF_CATEG_ID和SITE_ID沒有選擇,那麼USER_DEFINED_FIELD1和USER_DEFINED_FIELD3做爲衍生列,那麼衍生列有什麼用呢??看我和我朋友的聊天記錄:

3.2.3 BUYER_ACCOUNT 維度選擇遇到的問題

發現鏈接鍵ACCOUNT_ID沒有選擇,另外無關列ACCOUNT_SELLER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY更名爲BUYER_COUNTRY,以下所示:

3.2.4 SELLER_ACCOUNT 維度選擇遇到的問題

發現鏈接鍵ACCOUNT_ID沒有選擇,另外無關列ACCOUNT_BUYER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY更名爲SELLER_COUNTRY,以下所示:

3.2.5 BUYER_COUNTRY 和 SELLER_COUNTRY 維度選擇遇到的問題

發現鏈接鍵COUNTRY沒有選擇,另外 NAME更名爲BUYER_COUNTRY_NAME和SELLER_COUNTRY_NAME。

3.3 官方案例度量選擇

主要的聚合方式有:COUNT、SUM、MIN、MAX、PERCENTILE,下面將詳細介紹其餘幾種聚合方式:

3.3.1 Count Distinct 理論知識:

Apache Kylin提供了兩種Count Distinct計算方式,一種是近似的,一種是精確的,精確的Count Distinct指標在Build時候 會消耗更多的資源(內存和存儲),Build的過程也比較慢。

近似Count Distinct Apache Kylin使用HyperLogLog算法實現了近似Count Distinct,提供了錯誤率從9.75%到1.22%幾種精度供選擇; 算法計算後的Count Distinct指標,理論上,結果最大隻有64KB,最低的錯誤率是1.22%; 這種實現方式用在須要快速計算、節省存儲空間,而且能接受錯誤率的Count Distinct指標計算。

精準Count Distinct Kylin中實現了基於bitmap的精確Count Distinct計算方式。當數據類型爲tiny int(byte)、small int(short)以及int, 會直接將數據值映射到bitmap中;當數據類型爲long,string或者其餘,則須要將數據值以字符串形式編碼成dict(字典),再將字典ID映射到bitmap; 指標計算後的結果,並非計數後的值,而是包含了序列化值的bitmap.這樣,才能確保在任意維度上的Count Distinct結果是正確的。 這種實現方式提供了精確的無錯誤的Count Distinct結果,可是須要更多的存儲資源,若是數據中的不重 復值超過百萬,結果所佔的存儲應該會達到幾百MB。

3.3.2 EXTEND_COLUMN 理論知識:

Extended Column 在OLAP分析場景中,常常存在對某個id進行過濾,但查詢結果要展現爲name的狀況,好比user_id和user_name。這類問題一般有三種解決方式:

  • a. 將ID和Name都設置爲維度,查詢語句相似select name, count(*) from table where id = 1 group by id,name。這種方式的問題是會致使維度增多,致使預計算結果膨脹;
  • b. 將id和name都設置爲維度,而且將二者設置爲聯合。這種方式的好處是保持維度組合數不會增長,但限制了維度的其它優化,好比ID不能再被設置爲強制維度或者層次維度;
  • c. 將ID設置爲維度,Name設置爲特殊的Measure,類型爲Extended Column。這種方式既能保證過濾id且查詢name的需求,同時也不影響id維度的進一步優化。

3.4 Count Distinct和TopN 官方案例講解:

3.4.1 Count Distinct案例,主要用於對訂單去重,錯誤率要求小於必定百分比

3.4.2 TopN 案例,主要用於按照seller_id 進行分組,而後對price進行聚合操做,實現每一筆訂單的銷售總額

3.5 cube中Messures總覽

4 官方案例Refresh Setting 設置

  • Auto Merge Thresholds :自動合併閾值,按天增長的segement,每7天合併一次;7天的segment每28天合併一次
  • Retention Threshold:默認爲0,保留歷史全部的segment。
  • Volatile Range: 默認爲 0,‘Auto Merge’ 會自動合併全部可能的 cube segments;設置具體的數值後,‘Auto Merge’ 將不會合並最近 Volatile Range 天的 cube segments;假設 Volatile Range 設置爲 7,則最近 7 天內生成的 cube segments 不會被自動合併;
  • Partition Start Date:分區開始時間

4.1 官方案例Refresh Setting 強制維度設置

和朋友進行反覆確認的 強制維度,這裏官方案例真的出現了,在進行查詢的時候,PART_DT不出現也是能夠的,爲何呢?請參考下面的解釋

Mandatory 維度指的是那些老是會出現 在Where 條件或 Group By 語句裏的維度。固然必須存在不必定是顯式出如今查詢語句中,例如查詢日期是必要字段,月份、季度、年屬於它的衍生字段,那麼查詢的時候出現月份、季度、年這些衍生字段等效於出現查詢日期這個必要字段。

4.2 官方案例Refresh Setting層次維度的設置

能夠看到官方案例按照層次順序,進行cubeId的構建,根據綁定關係,進行了剪枝處理

4.3 官方案例Refresh Setting聯合維度的設置

根據綁定關係,進行了剪枝處理

4.4 Rokeys 的設置

各維度在 Rowkeys 中的順序,對於查詢的性能會產生較明顯的影響;在這裏用戶能夠根據查詢的模式和習慣,經過拖曳的方式調整各個維度在Rowkeys上的順序。推薦的順序爲:Mandatory 維度、where 過濾條件中出現頻率較多的維度、高基數維度、低基數維度。這樣作的好處是,充分利用過濾條件來縮小在 HBase 中掃描的範圍,從而提升查詢的效率。

咱們發現不經常使用維度放在了後面:

5 官方案例總覽

發現總共使用了20個維度和6個度量,以及6個Lookup Table (包含別名表)

6 官方案例構建CUBE

7 官方案例測試

在進行Cube構建時,我沒有選擇鏈接鍵和衍生維度(主鍵),那麼能不能正常使用,讓咱們拭目以待,如下是維度剪枝優化的內容,基於此,咱們來作測試:

7.1 測試一:Joint Dimension 缺乏夥伴是否會報錯?

7.1.1 訂單事實表與訂單類別表的聯合查詢:

7.1.2 結論:聯合維度確實同伴不會報錯

7.2 測試二:衍生維度可否正常分組和條件過濾?

7.2.1 訂單事實表與時間維度表進行衍生字段分組:

7.2.2 結論:衍生維度分組不會報錯

7.2.2 訂單事實表與時間維度表進行衍生字段分組+過濾:

7.2.3 結論:衍生維度過濾不會報錯

7.3 測試三:Mandatory Dimensions 缺乏是否報錯?

若是強制維度是衍生維度所在表的鏈接鍵(即KYLIN_SALES 與 KYLIN_CAL_DT的鏈接鍵CAL_DT)在,那麼查詢時不包含強制維度也不會不錯,參考7.2.1既能夠看出來。

7.3.1 結論:KYLIN_SALES.PART_DT缺乏不會報錯,雖然被設置成強制維度

7.4 測試四:層次維度亂序會不會報錯呢?

能夠看到隨便更改層次維度順序,都不會報錯,原則上已經作過優化:

看我和一個朋友的聊天記錄,感謝我這位朋友技術支持:

7.4.1 結論:不會報錯

應該這樣理解,層次維度ABC,AB , A 包含了全部維度組合狀況狀況,因此就不用其餘的組合了,計算BC實際上查的仍是ABC,因此Kylin經過層次維度設置,縮減了cubeId的數量。

8 結語

至此 ,整個官方案例剖析完畢,而留給咱們的思考又該何時結束呢?Kylin做爲OLAP技術先驅,真正把HBASE的列式存儲功能發揮到了極致,沒有HBASE和SPARK做爲技術支撐,KYLIN又該是什麼呢?若是有機會,我會寫一篇HBASE技術專欄,咱們來看看Hbase如何基於LSM(Log-Structured Merge Tree)把索引即數據的思想給落地的。如對spark感興趣請關注個人Spark技術架構剖析專欄。

秦凱新 於深圳 2018-10-30

相關文章
相關標籤/搜索