版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。版權聲明:禁止轉載,歡迎學習。算法
Kylin官方案例是一個很是經典的案例,包含的技術細節經過深挖能呈現出更具價值的信息,如:數據倉庫理論,星型模型,雪花模型,角色扮演維度,維度剪枝等。相信您會經過個人深刻剖析,有一種恍然大悟的感受。官方案例是一個訂單案例,其中包含了訂單事實表,訂單日期表,商品分類維度,帳號維度(購買者和銷售者)以及區域維度(購買者和銷售者)。數據庫
對 「Add Lookup Table」 頁面的幾點說明:緩存
從原始的hive維度表中順序得讀取每一行每一列的值;架構
使用 TrieDictionary 方式對這些全部的值進行編碼(一個值對應一個 Id);併發
再次讀取原始表中每一行的值,將每一列的值使用編碼以後的 Id 進行替換,獲得了一個只有 Id 的新表;高併發
同時保存這個新表和 Dictionary 對象(Id 和值的映射關係)就可以保存整個維度表;post
Kylin 將這個數據存儲到元數據庫中。性能
該處Snapshot Table 總結的很好,因此標明引用地址:https://juejin.im/post/5bcf370d6fb9a05cff3255dd
複製代碼
在 Dimensions 頁面選擇可能參與計算的維度,這裏被選擇的只是在 Cube 構建的時候擁有被選擇資格的維度,並非最後參與 Cube 構建的維度,推薦將維度表中的字段都選擇上。 以下展現了Dimensions的選擇:學習
對於BUYER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構建 測試
對於SELLER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構建
同理如上
在 Measures 頁面選擇可能用於計算的度量。通常而言,銷售額、流量、溫溼度等會做爲度量。
在 Settings 頁面能夠設置分區以及過濾條件,其中分區是爲了系統能夠進行增量構建而設計的,目前 Kylin 支持基於日期的分區,在 「Partition Date Column」 後面選擇事實表或者維度表中的日期字段,而後選擇日期格式便可;過濾條件設置後,Kylin 在構建的時候會選擇符合過濾條件的數據進行構建。 須要注意的幾點:
在選擇維度時,每個維度列能夠做爲普通維度(Normal),也能夠做爲衍生維度(Derived)。相對於普通維度來講,衍生維度並不參與維度的 Cuboid,衍生維度對應的外鍵(FK)參與維度 Cuboid,從而下降 Cuboid 數。在查詢時,對衍生維度的查詢會首先轉換爲對外鍵所在維度的查詢,所以會犧牲少許性能(大部分狀況下能夠接受)。
如何進行維度優化,首先請確認你設置的cube維度都是你查詢時會使用到的。
目前Kylin可使用的維度優化手段有如下幾種:
在一個多維數據集合中,維度的個數決定着維度之間可能的組合數,而每個維度中成員集合的大小決定着每個可能的組合的個數,例若有三個普通的維度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。
這種維度意味着每次查詢的group by中都會攜帶的,將某一個dimension設置爲mandatory能夠將cuboid的個數減小一半,以下圖:
這種維度是最多見的,尤爲是在mondrian中,咱們對於多維數據的操做常常會有上卷下鑽之類的操做,這也就須要要求維度之間有層級關係,例如國家、省、城市,年、季度、月等。有層級關係的維度也能夠大大減小cuboid的個數。以下圖:
這類維度的意思是可推導的維度,須要該維度對應的一個或者多個列能夠和維度表的主鍵是一對一的,這種維度能夠大大減小cuboid個數,以下圖:
例如timeid是時間這個維度表的主鍵,也就是事實表的外鍵,時間只精確到天,那麼year、month、day三列能夠惟一對應着一個time_id,而time_id是事實表的外鍵,那麼咱們能夠指定year、month、day爲一個derived維度,實際存儲的時候能夠只根據timeid的取值決定維度的組合,但這就要求咱們在查詢的時候使用的group by必須指定derived維度集合中的全部列。 3.聯合維度(Joint) 每個聯合維度包括兩個或者更多的維度,聯合維度內的維度,要麼不出現,要麼必須一塊兒出現。不一樣的聯合之間不該當有共同的維度
聯合維度:將幾個維度視爲一個維度。 適用場景:
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]
SELECT cal_dt, city, sex_id, count(*) FROM table GROUP BY cal_dt, city, sex_id
則它將從Cuboid [cal_dt, city, sex_id]中獲取數據
複製代碼
若是有一條不經常使用的查詢:
SELECT cal_dt, city, count(*) FROM table GROUP BY cal_dt, city
則沒有現成的徹底匹配的 Cuboid,Apache Kylin 會經過在線計算的方式,從現有的 Cuboid 中計算出最終結果。
複製代碼
粒度優化對應的是提升Cube的併發度,其設置是在自定義屬性中的 一共有三個屬性能夠提升併發度。 1.kylin.hbase.region.cut(共使用幾個分區) 2.kylin.hbase.region.count.min(最少使用幾個分區) 3.kylin.hbase.region.count.max(最多使用幾個分區)
根據相對應的狀況調高最少使用分區,下降最大使用分區,可以有效增長系統的並行度。
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)
複製代碼
發現鏈接鍵沒有勾選,如:LEAF_CATEG_ID 和LSTG_SITE_ID是外鍵,PART_DT 的是衍生外鍵也沒有選擇,所以,意味着在CUBE構建時,只用關心計算維度,鏈接鍵雖然不選擇,衍生維度仍是生效的:
維度選擇,發現鏈接鍵LEAF_CATEG_ID和SITE_ID沒有選擇,那麼USER_DEFINED_FIELD1和USER_DEFINED_FIELD3做爲衍生列,那麼衍生列有什麼用呢??看我和我朋友的聊天記錄:
發現鏈接鍵ACCOUNT_ID沒有選擇,另外無關列ACCOUNT_SELLER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY更名爲BUYER_COUNTRY,以下所示:
發現鏈接鍵ACCOUNT_ID沒有選擇,另外無關列ACCOUNT_BUYER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY更名爲SELLER_COUNTRY,以下所示:
發現鏈接鍵COUNTRY沒有選擇,另外 NAME更名爲BUYER_COUNTRY_NAME和SELLER_COUNTRY_NAME。
主要的聚合方式有:COUNT、SUM、MIN、MAX、PERCENTILE,下面將詳細介紹其餘幾種聚合方式:
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。
Extended Column 在OLAP分析場景中,常常存在對某個id進行過濾,但查詢結果要展現爲name的狀況,好比user_id和user_name。這類問題一般有三種解決方式:
和朋友進行反覆確認的 強制維度,這裏官方案例真的出現了,在進行查詢的時候,PART_DT不出現也是能夠的,爲何呢?請參考下面的解釋
能夠看到官方案例按照層次順序,進行cubeId的構建,根據綁定關係,進行了剪枝處理
根據綁定關係,進行了剪枝處理
各維度在 Rowkeys 中的順序,對於查詢的性能會產生較明顯的影響;在這裏用戶能夠根據查詢的模式和習慣,經過拖曳的方式調整各個維度在Rowkeys上的順序。推薦的順序爲:Mandatory 維度、where 過濾條件中出現頻率較多的維度、高基數維度、低基數維度。這樣作的好處是,充分利用過濾條件來縮小在 HBase 中掃描的範圍,從而提升查詢的效率。
咱們發現不經常使用維度放在了後面:
發現總共使用了20個維度和6個度量,以及6個Lookup Table (包含別名表)
在進行Cube構建時,我沒有選擇鏈接鍵和衍生維度(主鍵),那麼能不能正常使用,讓咱們拭目以待,如下是維度剪枝優化的內容,基於此,咱們來作測試:
若是強制維度是衍生維度所在表的鏈接鍵(即KYLIN_SALES 與 KYLIN_CAL_DT的鏈接鍵CAL_DT)在,那麼查詢時不包含強制維度也不會不錯,參考7.2.1既能夠看出來。
能夠看到隨便更改層次維度順序,都不會報錯,原則上已經作過優化:
應該這樣理解,層次維度ABC,AB , A 包含了全部維度組合狀況狀況,因此就不用其餘的組合了,計算BC實際上查的仍是ABC,因此Kylin經過層次維度設置,縮減了cubeId的數量。
至此 ,整個官方案例剖析完畢,而留給咱們的思考又該何時結束呢?Kylin做爲OLAP技術先驅,真正把HBASE的列式存儲功能發揮到了極致,沒有HBASE和SPARK做爲技術支撐,KYLIN又該是什麼呢?若是有機會,我會寫一篇HBASE技術專欄,咱們來看看Hbase如何基於LSM(Log-Structured Merge Tree)把索引即數據的思想給落地的。如對spark感興趣請關注個人Spark技術架構剖析專欄。
秦凱新 於深圳 2018-10-30