Kylin官方案例詳細(xì)剖析及剪枝優(yōu)化-OLAP商業(yè)環(huán)境實(shí)戰(zhàn)

版權(quán)聲明:本套技術(shù)專欄是作者(秦凱新)平時(shí)工作的總結(jié)和升華,通過從真實(shí)商業(yè)環(huán)境抽取案例進(jìn)行總結(jié)和分享,并給出商業(yè)應(yīng)用的調(diào)優(yōu)建議和集群環(huán)境容量規(guī)劃等內(nèi)容,請(qǐng)持續(xù)關(guān)注本套博客。版權(quán)聲明:禁止轉(zhuǎn)載,歡迎學(xué)習(xí)。

Kylin官方案例是一個(gè)非常經(jīng)典的案例,包含的技術(shù)細(xì)節(jié)通過深挖能呈現(xiàn)出更具價(jià)值的信息,如:數(shù)據(jù)倉庫理論,星型模型,雪花模型,角色扮演維度,維度剪枝等。相信您會(huì)通過我的深入剖析,有一種恍然大悟的感覺。官方案例是一個(gè)訂單案例,其中包含了訂單事實(shí)表,訂單日期表,商品分類維度,賬號(hào)維度(購買者和銷售者)以及區(qū)域維度(購買者和銷售者)。

一 Kylin官方案例表關(guān)系及字段詳解

1.1 Kylin官方案例表簡要說明

  • KYLIN_SALES是事實(shí)表,保存了銷售訂單的明細(xì)信息。各列分別保存著賣家、商品分類、訂單金額、商品數(shù)量等信息,每一行對(duì)應(yīng)著一筆交易訂單。
  • KYLIN_CATEGORY_GROUPINGS是維表,保存了商品分類的詳細(xì)介紹,例如商品分類名稱等。
  • KYLIN_CAL_DT也是維表,保存了時(shí)間的擴(kuò)展信息。如單個(gè)日期所、月始、周始、年份、月份等。
  • KYLIN_ACCOUNT也是維表,作為角色扮演維度,包含購買者和開發(fā)者賬號(hào)。
  • KYLIN_COUNTRY包含區(qū)域維度,作為角色扮演維度,包含購買者和開發(fā)者所在區(qū)域信息。

1.2 KYLIN_SALES 事實(shí)表字段詳解:

image

1.3 KYLIN_CATEGORY_GROUPINGS 字段說明 :

1.3.1 KYLIN_CATEGORY_GROUPINGS主要字段:

  • LEAF_CATEG_ID:主鍵
  • SITE_ID:外鍵


    image

1.3.2 KYLIN_CATEGORY_GROUPINGS 對(duì)外連接關(guān)系:

image

1.3.3 KYLIN_CATEGORY_GROUPINGS 主要字段解釋:

image

1.4 KYLIN_COUNTRY 主要字段詳解:

image

1.5 KYLIN_ACCOUNT 主要字段詳解:

image

1.6 雪花模型關(guān)系總覽:

image

二 建立模型(Model)

2.1 Kylin 官方模型 model關(guān)系圖如下:

image

2.2 第一步:雪花和星型模型,建立inner join關(guān)系,重要的是確定字段關(guān)聯(lián),對(duì)于角色維度(KYLIN_ACCOUNT和KYLIN_COUNTRY),需要?jiǎng)e名處理。

對(duì) “Add Lookup Table” 頁面的幾點(diǎn)說明:

  1. 數(shù)據(jù)關(guān)系不僅僅是事實(shí)表與維度表之間(星型模型),維度表和維度表之間(雪花模型)也可以建立聯(lián)系;
  2. 表與表之間的連接添加有三種:“Left Join”、“Inner Join”、“Right Join”;
  3. Skip snapshot for this lookup table 選項(xiàng)指的是是否跳過生成 snapshotTable,由于某些 Lookup 表特別大(大于 300M),如果某一個(gè)維度的基數(shù)比較大 ,可能會(huì)導(dǎo)致內(nèi)存出現(xiàn) OOM,所以在創(chuàng)建 snapshotTable 的時(shí)候會(huì)限制原始表的大小不能超過配置的一個(gè)上限值(kylin.snapshot.max-mb,默認(rèn)值300);
  4. 跳過構(gòu)建 snapshot 的 lookup 表將不能搜索,同時(shí)不支持設(shè)置為衍生維度(Derived);
  5. 大部分情況下都是使用 “Left Join”,其他兩種 Join 方式不是很常用。

2.2.1 每一個(gè) Snapshot 是和一個(gè) Hive 維度表對(duì)應(yīng)的,生成的過程是:

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

  • 使用 TrieDictionary 方式對(duì)這些所有的值進(jìn)行編碼(一個(gè)值對(duì)應(yīng)一個(gè) Id);

  • 再次讀取原始表中每一行的值,將每一列的值使用編碼之后的 Id 進(jìn)行替換,得到了一個(gè)只有 Id 的新表;

  • 同時(shí)保存這個(gè)新表和 Dictionary 對(duì)象(Id 和值的映射關(guān)系)就能夠保存整個(gè)維度表;

  • Kylin 將這個(gè)數(shù)據(jù)存儲(chǔ)到元數(shù)據(jù)庫中。

      該處Snapshot Table 總結(jié)的很好,所以標(biāo)明引用地址:https://juejin.im/post/5bcf370d6fb9a05cff3255dd
    

2.2.2 雪花模型關(guān)系圖

image

2.3 第二步:資格維度選擇:

在 Dimensions 頁面選擇可能參與計(jì)算的維度,這里被選擇的只是在 Cube 構(gòu)建的時(shí)候擁有被選擇資格的維度,并不是最后參與 Cube 構(gòu)建的維度,推薦將維度表中的字段都選擇上。
如下展示了Dimensions的選擇:

  • 對(duì)于KYLIN_SALES,其中SLR_SEGMENT_CD,PRICE,ITEM_COUNT沒有選擇,所以沒有資格參與cubeId構(gòu)建
image
  • 對(duì)于KYLIN_CAL_DT,其中僅選擇了部分參與的維度,其他沒有資格參與cubeId構(gòu)建
image
  • 對(duì)于KYLIN_CATEGORY_GROUPING,其中僅選擇了部分參與的維度,其他沒有資格參與cubeId構(gòu)建
image
  • 對(duì)于BUYER_ACCOUNT 與 SELLER_ACCOUNT,全部有資格參與cubeId構(gòu)建
image
  • 對(duì)于BUYER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構(gòu)建


    image
  • 對(duì)于SELLER_COUNTRY,只有COUNTRY , NAME 有資格參與cubeId構(gòu)建

同理如上

2.3.1 資格維度選擇結(jié)果總覽:

image

2.4 第三步: Measures 度量指標(biāo)選擇:

在 Measures 頁面選擇可能用于計(jì)算的度量。一般而言,銷售額、流量、溫濕度等會(huì)作為度量。

image

2.5 第四步:Settings設(shè)置

在 Settings 頁面可以設(shè)置分區(qū)以及過濾條件,其中分區(qū)是為了系統(tǒng)可以進(jìn)行增量構(gòu)建而設(shè)計(jì)的,目前 Kylin 支持基于日期的分區(qū),在 “Partition Date Column” 后面選擇事實(shí)表或者維度表中的日期字段,然后選擇日期格式即可;過濾條件設(shè)置后,Kylin 在構(gòu)建的時(shí)候會(huì)選擇符合過濾條件的數(shù)據(jù)進(jìn)行構(gòu)建。
需要注意的幾點(diǎn):

  1. 時(shí)間分區(qū)列可以支持日期或更細(xì)粒度的時(shí)間分區(qū);
  2. 時(shí)間分區(qū)列支持的數(shù)據(jù)類型有 time/date/datetime/integer等;
  3. 過濾條件不需要寫 WHERE;
  4. 過濾條件不能包含日期維度。
image

三 構(gòu)建cube模型

3.1 維度選擇

在選擇維度時(shí),每一個(gè)維度列可以作為普通維度(Normal),也可以作為衍生維度(Derived)。相對(duì)于普通維度來說,衍生維度并不參與維度的 Cuboid,衍生維度對(duì)應(yīng)的外鍵(FK)參與維度 Cuboid,從而降低 Cuboid 數(shù)。在查詢時(shí),對(duì)衍生維度的查詢會(huì)首先轉(zhuǎn)換為對(duì)外鍵所在維度的查詢,因此會(huì)犧牲少量性能(大部分情況下可以接受)。

3.1.1 維度剪枝優(yōu)化

如何進(jìn)行維度優(yōu)化,首先請(qǐng)確認(rèn)你設(shè)置的cube維度都是你查詢時(shí)會(huì)使用到的。

目前Kylin可以使用的維度優(yōu)化手段有以下幾種:

  • 聚集組
  • 衍生緯度
  • 強(qiáng)制維度
  • 層次維度
  • 聯(lián)合維度
  • Extended Column

在一個(gè)多維數(shù)據(jù)集合中,維度的個(gè)數(shù)決定著維度之間可能的組合數(shù),而每一個(gè)維度中成員集合的大小決定著每一個(gè)可能的組合的個(gè)數(shù),例如有三個(gè)普通的維度A、B、C,他們的不同成員數(shù)分別為10/100/1000,那么一個(gè)維度的組合有2的3次方個(gè),分別是{空、A、B、C、AB、BC、AC、ABC},每一個(gè)成員我們稱為cuboid(維度的組合),而這些集合的成員組合個(gè)數(shù)分別為1、10、100、1000、10*100、100 1000、101000和10 *100 *1000。我們稱每一個(gè)dimension中不同成員個(gè)數(shù)為cardinatily,我們要盡量避免存儲(chǔ)cardinatily比較高的維度的組合。

在上面的例子中我們可以不緩存BC和C這兩個(gè)cuboid,可以通過計(jì)算的方式通過ABC中成員的值計(jì)算出BC或者C中某個(gè)成員組合的值,這相當(dāng)于是時(shí)間和空間的一個(gè)權(quán)衡吧。在kylin中存在的四種維度是為了減少cuboid的個(gè)數(shù),而不是每一個(gè)維度是否緩存的,當(dāng)前kylin是對(duì)所有的cuboid中的所有組合都進(jìn)行計(jì)算和存儲(chǔ)的,對(duì)于普通的dimension,從上面的例子中可以看出N個(gè)維度的cuboid個(gè)數(shù)為2的N次方,而kylin中設(shè)置了一些維度可以減少cuboid個(gè)數(shù),當(dāng)然,這需要使用者對(duì)自己需要的維度十分了解,知道自己可能根據(jù)什么進(jìn)行g(shù)roup by。

3.1.2 Mandatory維度

這種維度意味著每次查詢的group by中都會(huì)攜帶的,將某一個(gè)dimension設(shè)置為mandatory可以將cuboid的個(gè)數(shù)減少一半,如下圖:


image

這是因?yàn)槲覀兇_定每一次group by都會(huì)攜帶A,那么就可以省去所有不包含A這個(gè)維度的cuboid了。

3.1.3 hierarchy維度

這種維度是最常見的,尤其是在mondrian中,我們對(duì)于多維數(shù)據(jù)的操作經(jīng)常會(huì)有上卷下鉆之類的操作,這也就需要要求維度之間有層級(jí)關(guān)系,例如國家、省、城市,年、季度、月等。有層級(jí)關(guān)系的維度也可以大大減少cuboid的個(gè)數(shù)。如下圖:

image

這里僅僅局限于A/B/C是一個(gè)層級(jí),例如A是年份,B是季度、C是月份,那么查詢的時(shí)候可能的組合只有年、xx年的季度、xx年xx季度的xx月,這就意味著我們不能再單獨(dú)的對(duì)季度和月份進(jìn)行聚合了,例如我們查詢的時(shí)候不能使用group by month,而必須使用group by year,quart,month。如果需要單獨(dú)的對(duì)month進(jìn)行聚合,那么還需要再使用month列定義一個(gè)單獨(dú)的普通維度。

3.1.4 derived維度

這類維度的意思是可推導(dǎo)的維度,需要該維度對(duì)應(yīng)的一個(gè)或者多個(gè)列可以和維度表的主鍵是一對(duì)一的,這種維度可以大大減少cuboid個(gè)數(shù),如下圖:

image

例如timeid是時(shí)間這個(gè)維度表的主鍵,也就是事實(shí)表的外鍵,時(shí)間只精確到天,那么year、month、day三列可以唯一對(duì)應(yīng)著一個(gè)time_id,而time_id是事實(shí)表的外鍵,那么我們可以指定year、month、day為一個(gè)derived維度,實(shí)際存儲(chǔ)的時(shí)候可以只根據(jù)timeid的取值決定維度的組合,但這就要求我們?cè)诓樵兊臅r(shí)候使用的group by必須指定derived維度集合中的所有列。
3.聯(lián)合維度(Joint)
每一個(gè)聯(lián)合維度包括兩個(gè)或者更多的維度,聯(lián)合維度內(nèi)的維度,要么不出現(xiàn),要么必須一起出現(xiàn)。不同的聯(lián)合之間不應(yīng)當(dāng)有共同的維度

3.1.5 聯(lián)合維度

聯(lián)合維度:將幾個(gè)維度視為一個(gè)維度。
適用場景:

  • 1 可以將確定在查詢時(shí)一定會(huì)同時(shí)使用的幾個(gè)維度設(shè)為一個(gè)聯(lián)合維度。

  • 2 可以將基數(shù)很小的幾個(gè)維度設(shè)為一個(gè)聯(lián)合維度。

  • 3 可以將查詢時(shí)很少使用的幾個(gè)維度設(shè)為一個(gè)聯(lián)合維度。

優(yōu)化效果:將N個(gè)維度設(shè)置為聯(lián)合維度,則這N個(gè)維度組合成的cuboid個(gè)數(shù)會(huì)從2的N次方減少到1。

應(yīng)用實(shí)例:

假設(shè)創(chuàng)建一個(gè)交易數(shù)據(jù)的Cube,它具有很多普通的維度,像是交易日期 cal_dt,交易的城市 city,顧客性別 sex_id 和支付類型 pay_type 等。分析師常用的分析方法為通過按照交易時(shí)間、交易地點(diǎn)和顧客性別來聚合,獲取不同城市男女顧客間不同的消費(fèi)偏好,例如同時(shí)聚合交易日期 cal_dt、交易的城市 city 和顧客性別 sex_id來分組。
聚合組:[cal_dt, city, sex_id,pay_type]
聯(lián)合維度: [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]中獲取數(shù)據(jù)
Case2:

如果有一條不常用的查詢:

 SELECT cal_dt, city, count(*) FROM table GROUP BY cal_dt, city
 則沒有現(xiàn)成的完全匹配的 Cuboid,Apache Kylin 會(huì)通過在線計(jì)算的方式,從現(xiàn)有的 Cuboid 中計(jì)算出最終結(jié)果。

3.1.6 粒度優(yōu)化

粒度優(yōu)化對(duì)應(yīng)的是提高Cube的并發(fā)度,其設(shè)置是在自定義屬性中的
一共有三個(gè)屬性可以提高并發(fā)度。
1.kylin.hbase.region.cut(共使用幾個(gè)分區(qū))
2.kylin.hbase.region.count.min(最少使用幾個(gè)分區(qū))
3.kylin.hbase.region.count.max(最多使用幾個(gè)分區(qū))

根據(jù)相對(duì)應(yīng)的情況調(diào)高最少使用分區(qū),降低最大使用分區(qū),能夠有效增加系統(tǒng)的并行度。

3.1.7 RowKey優(yōu)化

Rowkeys: 是由維度編碼值組成。”Dictionary” (字典)是默認(rèn)的編碼方式; 字典只能處理中低基數(shù)(少于一千萬)的維度;如果維度基數(shù)很高(如大于1千萬), 選擇 “false” 然后為維度輸入合適的長度,通常是那列的最大長度值; 如果超過最大值,會(huì)被截?cái)唷U?qǐng)注意,如果沒有字典編碼,cube 的大小可能會(huì)非常大。
你可以拖拽維度列去調(diào)整其在 rowkey 中位置; 位于rowkey前面的列,將可以用來大幅縮小查詢的范圍。通常建議將 mandantory 維度放在開頭, 然后是在過濾 ( where 條件)中起到很大作用的維度;如果多個(gè)列都會(huì)被用于過濾,將高基數(shù)的維度(如 user_id)放在低基數(shù)的維度(如 age)的前面。

Kylin 以 Key-Value 的方式將 Cube 存儲(chǔ)到 HBase 中,HBase 的 key,也就是 Rowkey,是由各維度的值拼接而成的;為了更高效地存儲(chǔ)這些值,Kylin 會(huì)對(duì)它們進(jìn)行編碼和壓縮;每個(gè)維度均可以選擇合適的編碼(Encoding)方式,默認(rèn)采用的是字典(Dictionary)編碼技術(shù);字段支持的基本編碼類型如下:

  • dict:適用于大部分字段,默認(rèn)推薦使用,但在超高基情況下,可能引起內(nèi)存不足的問題;對(duì)于使用該種編碼的維度,每個(gè)Segment在構(gòu)建的時(shí)候都會(huì)為這個(gè)維度所有可能的值創(chuàng)建一個(gè)字典,然后使用字典中每個(gè)值的編號(hào)來編碼。Dict的優(yōu)勢是產(chǎn)生的編碼非常緊湊,尤其在維度值的基數(shù)較小且長度較大的情況下,特別節(jié)約空間。由于產(chǎn)生的字典是在查詢時(shí)加載入構(gòu)建引擎和查詢引擎的,所以在維度的基數(shù)大、長度也大的情況下,容易造成構(gòu)建引擎或查詢引擎的內(nèi)存溢出。

  • boolean:適用于字段值為true, false, TRUE, FALSE, True, False, t, f, T, F, yes, no, YES, NO, Yes, No, y, n, Y, N, 1, 0;

  • integer:適用于字段值為整數(shù)字符,支持的整數(shù)區(qū)間為[ -2^(8N-1), 2^(8N-1)];Integer編碼需要提供一個(gè)額外的參數(shù)“Length”來代表需要多少個(gè)字節(jié)。Length的長度為1~8。如果用來編碼int32類型的整數(shù),可以將Length設(shè)為4;如果用來編碼int64類型的整數(shù),可以將Length設(shè)為8。在更多情況下,如果知道一個(gè)整數(shù)類型維度的可能值都很小,那么就能使用Length為2甚至是1的int編碼來存儲(chǔ),這將能夠有效避免存儲(chǔ)空間的浪費(fèi)。

  • date:適用于字段值為日期字符,支持的格式包括yyyyMMdd、yyyy-MM-dd、yyyy-MM-dd HH:mm:ss、yyyy-MM-dd HH:mm:ss.SSS,其中如果包含時(shí)間戳部分會(huì)被截?cái)啵粚⑷掌陬愋偷臄?shù)據(jù)使用三個(gè)字節(jié)進(jìn)行編碼,其支持從0000-01-01到9999-01-01中的每一個(gè)日期。

  • time:適用于字段值為時(shí)間戳字符,支持范圍為[ 1970-01-01 00:00:00, 2038/01/19 03:14:07],毫秒部分會(huì)被忽略,time編碼適用于 time, datetime, timestamp 等類型;Time編碼僅僅支持到秒。但是Time編碼的優(yōu)勢是每個(gè)維度僅僅使用4個(gè)字節(jié),這相比普通的長整數(shù)編碼節(jié)約了一半。如果能夠接受秒級(jí)的時(shí)間精度,請(qǐng)選擇Time編碼來代表時(shí)間的維度。

  • fix_length:適用于超高基場景,將選取字段的前 N 個(gè)字節(jié)作為編碼值,當(dāng) N 小于字段長度,會(huì)造成字段截?cái)啵?dāng) N 較大時(shí),造成 RowKey 過長,查詢性能下降,只適用于 varchar 或 nvarchar 類型;編碼需要提供一個(gè)額外的參數(shù)“Length”來代表需要多少個(gè)字節(jié)。該編碼可以看作Dict編碼的一種補(bǔ)充。對(duì)于基數(shù)大、長度也大的維度來說,使用Dict可能不能正常工作,于是可以采用一段固定長度的字節(jié)來存儲(chǔ)代表維度值的字節(jié)數(shù)組,該數(shù)組為字符串形式的維度值的UTF-8字節(jié)。如果維度值的長度大于預(yù)設(shè)的Length,那么超出的部分將會(huì)被截?cái)唷?/p>

  • fixed_length_hex:適用于字段值為十六進(jìn)制字符,比如 1A2BFF 或者 FF00FF,每兩個(gè)字符需要一個(gè)字節(jié),只適用于 varchar 或 nvarchar 類型。

  • 和Hbase 的RowKey優(yōu)化類似,在查詢的過程中,被用作過濾條件的維度可能放在其他維度的前面,經(jīng)常出現(xiàn)的維度應(yīng)該放在前面,基數(shù)比較大的維度應(yīng)該放在前面

      (參考鏈接:https://juejin.im/post/5bd5c59851882565e031f4be)
    

3.2:官方案例維度選擇

3.2.1 KYLIN_SALES維度選擇遇到的問題

發(fā)現(xiàn)連接鍵沒有勾選,如:LEAF_CATEG_ID 和LSTG_SITE_ID是外鍵,PART_DT 的是衍生外鍵也沒有選擇,因此,意味著在CUBE構(gòu)建時(shí),只用關(guān)心計(jì)算維度,連接鍵雖然不選擇,衍生維度還是生效的:

image
3.2.2 KYLIN_CAL_DT 維度選擇,發(fā)現(xiàn)ART_DT 的是衍生主鍵沒有勾選:
image
3.2.3 KYLIN_CATEGORY_GROUPINGS維度選擇遇到的問題

維度選擇,發(fā)現(xiàn)連接鍵LEAF_CATEG_ID和SITE_ID沒有選擇,那么USER_DEFINED_FIELD1和USER_DEFINED_FIELD3作為衍生列,那么衍生列有什么用呢??看我和我朋友的聊天記錄:

image
image
3.2.3 BUYER_ACCOUNT 維度選擇遇到的問題

發(fā)現(xiàn)連接鍵ACCOUNT_ID沒有選擇,另外無關(guān)列ACCOUNT_SELLER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY改名為BUYER_COUNTRY,如下所示:

image
3.2.4 SELLER_ACCOUNT 維度選擇遇到的問題

發(fā)現(xiàn)連接鍵ACCOUNT_ID沒有選擇,另外無關(guān)列ACCOUNT_BUYER_LEVEL和 ACCOUNT_CONTACT沒有被選擇,注意ACCOUNT_COUNTRY改名為SELLER_COUNTRY,如下所示:

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

發(fā)現(xiàn)連接鍵COUNTRY沒有選擇,另外 NAME改名為BUYER_COUNTRY_NAME和SELLER_COUNTRY_NAME。


image

3.3 官方案例度量選擇

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

3.3.1 Count Distinct 理論知識(shí):

Apache Kylin提供了兩種Count Distinct計(jì)算方式,一種是近似的,一種是精確的,精確的Count Distinct指標(biāo)在Build時(shí)候
會(huì)消耗更多的資源(內(nèi)存和存儲(chǔ)),Build的過程也比較慢。

近似Count Distinct
Apache Kylin使用HyperLogLog算法實(shí)現(xiàn)了近似Count Distinct,提供了錯(cuò)誤率從9.75%到1.22%幾種精度供選擇;
算法計(jì)算后的Count Distinct指標(biāo),理論上,結(jié)果最大只有64KB,最低的錯(cuò)誤率是1.22%;
這種實(shí)現(xiàn)方式用在需要快速計(jì)算、節(jié)省存儲(chǔ)空間,并且能接受錯(cuò)誤率的Count Distinct指標(biāo)計(jì)算。

精準(zhǔn)Count Distinct
Kylin中實(shí)現(xiàn)了基于bitmap的精確Count Distinct計(jì)算方式。當(dāng)數(shù)據(jù)類型為tiny int(byte)、small int(short)以及int,
會(huì)直接將數(shù)據(jù)值映射到bitmap中;當(dāng)數(shù)據(jù)類型為long,string或者其他,則需要將數(shù)據(jù)值以字符串形式編碼成dict(字典),再將字典ID映射到bitmap; 指標(biāo)計(jì)算后的結(jié)果,并不是計(jì)數(shù)后的值,而是包含了序列化值的bitmap.這樣,才能確保在任意維度上的Count Distinct結(jié)果是正確的。 這種實(shí)現(xiàn)方式提供了精確的無錯(cuò)誤的Count Distinct結(jié)果,但是需要更多的存儲(chǔ)資源,如果數(shù)據(jù)中的不重
復(fù)值超過百萬,結(jié)果所占的存儲(chǔ)應(yīng)該會(huì)達(dá)到幾百M(fèi)B。

image

3.3.2 EXTEND_COLUMN 理論知識(shí):

Extended Column
在OLAP分析場景中,經(jīng)常存在對(duì)某個(gè)id進(jìn)行過濾,但查詢結(jié)果要展示為name的情況,比如user_id和user_name。這類問題通常有三種解決方式:

  • a. 將ID和Name都設(shè)置為維度,查詢語句類似select name, count(*) from table where id = 1 group by id,name。這種方式的問題是會(huì)導(dǎo)致維度增多,導(dǎo)致預(yù)計(jì)算結(jié)果膨脹;
  • b. 將id和name都設(shè)置為維度,并且將兩者設(shè)置為聯(lián)合。這種方式的好處是保持維度組合數(shù)不會(huì)增加,但限制了維度的其它優(yōu)化,比如ID不能再被設(shè)置為強(qiáng)制維度或者層次維度;
  • c. 將ID設(shè)置為維度,Name設(shè)置為特殊的Measure,類型為Extended Column。這種方式既能保證過濾id且查詢name的需求,同時(shí)也不影響id維度的進(jìn)一步優(yōu)化。
image

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

3.4.1 Count Distinct案例,主要用于對(duì)訂單去重,錯(cuò)誤率要求小于一定百分比

image

3.4.2 TopN 案例,主要用于按照seller_id 進(jìn)行分組,然后對(duì)price進(jìn)行聚合操作,實(shí)現(xiàn)每一筆訂單的銷售總額

image

3.5 cube中Messures總覽

image

4 官方案例Refresh Setting 設(shè)置

  • Auto Merge Thresholds :自動(dòng)合并閾值,按天增加的segement,每7天合并一次;7天的segment每28天合并一次
  • Retention Threshold:默認(rèn)為0,保留歷史所有的segment。
  • Volatile Range: 默認(rèn)為 0,‘Auto Merge’ 會(huì)自動(dòng)合并所有可能的 cube segments;設(shè)置具體的數(shù)值后,‘Auto Merge’ 將不會(huì)合并最近 Volatile Range 天的 cube segments;假設(shè) Volatile Range 設(shè)置為 7,則最近 7 天內(nèi)生成的 cube segments 不會(huì)被自動(dòng)合并;
  • Partition Start Date:分區(qū)開始時(shí)間
image

4.1 官方案例Refresh Setting 強(qiáng)制維度設(shè)置

和朋友進(jìn)行反復(fù)確認(rèn)的 強(qiáng)制維度,這里官方案例真的出現(xiàn)了,在進(jìn)行查詢的時(shí)候,PART_DT不出現(xiàn)也是可以的,為什么呢?請(qǐng)參考下面的解釋

Mandatory 維度指的是那些總是會(huì)出現(xiàn) 在Where 條件或 Group By 語句里的維度。當(dāng)然必須存在不一定是顯式出現(xiàn)在查詢語句中,例如查詢?nèi)掌谑潜匾侄危路荨⒓径取⒛陮儆谒难苌侄危敲床樵兊臅r(shí)候出現(xiàn)月份、季度、年這些衍生字段等效于出現(xiàn)查詢?nèi)掌谶@個(gè)必要字段。
image

4.2 官方案例Refresh Setting層次維度的設(shè)置

可以看到官方案例按照層次順序,進(jìn)行cubeId的構(gòu)建,根據(jù)綁定關(guān)系,進(jìn)行了剪枝處理


image

4.3 官方案例Refresh Setting聯(lián)合維度的設(shè)置

根據(jù)綁定關(guān)系,進(jìn)行了剪枝處理

image

4.4 Rokeys 的設(shè)置

各維度在 Rowkeys 中的順序,對(duì)于查詢的性能會(huì)產(chǎn)生較明顯的影響;在這里用戶可以根據(jù)查詢的模式和習(xí)慣,通過拖曳的方式調(diào)整各個(gè)維度在Rowkeys上的順序。推薦的順序?yàn)椋篗andatory 維度、where 過濾條件中出現(xiàn)頻率較多的維度、高基數(shù)維度、低基數(shù)維度。這樣做的好處是,充分利用過濾條件來縮小在 HBase 中掃描的范圍,從而提高查詢的效率。


image

我們發(fā)現(xiàn)不常用維度放在了后面:


image

5 官方案例總覽

發(fā)現(xiàn)總共使用了20個(gè)維度和6個(gè)度量,以及6個(gè)Lookup Table (包含別名表)


image

6 官方案例構(gòu)建CUBE

image

7 官方案例測試

在進(jìn)行Cube構(gòu)建時(shí),我沒有選擇連接鍵和衍生維度( KYLIN_SALES.PART_DT = KYLIN_CAL_DT.CAL_DT),那么能不能正常使用,讓我們拭目以待,以下是維度剪枝優(yōu)化的內(nèi)容,基于此,我們來做測試:

image

7.1 測試一:Joint Dimension 缺少伙伴是否會(huì)報(bào)錯(cuò)?

7.1.1 訂單事實(shí)表與訂單類別表的聯(lián)合查詢:

image

7.1.2 結(jié)論

聯(lián)合維度缺失同伴不會(huì)報(bào)錯(cuò)

image

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

7.2.1 訂單事實(shí)表與時(shí)間維度表進(jìn)行衍生字段分組:

image

7.2.2 結(jié)論

衍生維度分組不會(huì)報(bào)錯(cuò)


image

7.2.2 訂單事實(shí)表與時(shí)間維度表進(jìn)行衍生字段分組+過濾:

image

7.2.3 結(jié)論

衍生維度過濾不會(huì)報(bào)錯(cuò)

image

7.3 測試三:Mandatory Dimensions 缺少是否報(bào)錯(cuò)?

如果強(qiáng)制維度是衍生維度所在表的連接鍵(即KYLIN_SALES 與 KYLIN_CAL_DT的連接鍵CAL_DT)在,那么查詢時(shí)不包含強(qiáng)制維度也不會(huì)不錯(cuò),參考7.2.1既可以看出來。

7.3.1 結(jié)論

KYLIN_SALES.PART_DT缺少不會(huì)報(bào)錯(cuò),雖然被設(shè)置成強(qiáng)制維度

7.4 測試四:層次維度亂序會(huì)不會(huì)報(bào)錯(cuò)呢?

可以看到隨便更改層次維度順序,都不會(huì)報(bào)錯(cuò),原則上已經(jīng)做過優(yōu)化:


image

看我和一個(gè)朋友的聊天記錄,感謝我這位朋友技術(shù)支持:


image

7.4.1 結(jié)論

不會(huì)報(bào)錯(cuò)
應(yīng)該這樣理解,層次維度ABC,AB , A 包含了所有維度組合情況情況,所以就不用其他的組合了,計(jì)算BC實(shí)際上查的還是ABC,所以Kylin通過層次維度設(shè)置,縮減了cubeId的數(shù)量。

8 結(jié)語

至此 ,整個(gè)官方案例剖析完畢,而留給我們的思考又該什么時(shí)候結(jié)束呢?Kylin作為OLAP技術(shù)先驅(qū),真正把HBASE的列式存儲(chǔ)功能發(fā)揮到了極致,沒有HBASE和SPARK作為技術(shù)支撐,KYLIN又該是什么呢?如果有機(jī)會(huì),我會(huì)寫一篇HBASE技術(shù)專欄,我們來看看Hbase如何基于LSM(Log-Structured Merge Tree)把索引即數(shù)據(jù)的思想給落地的。如對(duì)spark感興趣請(qǐng)關(guān)注我的Spark技術(shù)架構(gòu)剖析專欄。

秦凱新 于深圳 2018-10-30

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容