天天看點

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

目錄

一、Kylin增量建構

1、應用場景

2、了解Cube、Cuboid與Segment的關系

3、全量建構與增量建構  全量建構

4、增量建構Cube過程

5、增量Cube的 建立-案例

Kylin操作步驟

二、Cube碎片管理

1、增量建構的問題

2、管理Cube碎片

3、手動觸發合并Segment

3、删除Segment

4、自動合并

5、配置保留Segment

三、使用JDBC連接配接操作Kylin

四、Kylin Cube優化-Cuboid剪枝優化

1、為什麼要進行Cuboid剪枝優化

2、檢查Cuboid數量

3、檢查Cube大小

4、使用衍生次元

5、聚合組

一、Kylin增量建構

1、應用場景

        Kylin在每次Cube的建構都會從Hive中批量讀取資料,而對于大多數業務場景來說,Hive中的資料處于不斷增長的狀态。為了支援Cube中的資料能夠不斷地得到更新,且無需重複地為已經處理過的曆史資料建構Cube,是以對于Cube引入了

增量建構

的功能

2、了解Cube、Cuboid與Segment的關系

  • Kylin将Cube劃分為多個Segment(對應就是HBase中的一個表),每個Segment用起始時間和結束時間來辨別。
  • Segment代表一段時間内源資料的預計算結果。
  • 一個Segment的起始時間等于它之前那個Segment的結束時間,同理,它的結束時間等于它後面那個Segment的起始時間。
  • 同一個Cube下不同的Segment除了背後的源資料不同之外,其他如結構定義、建構過程、優化方法、存儲方式等都完全相同。
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

一個Cube,可以包含多個Cuboid,而Segment是指定時間範圍的Cube,可以了解為Cube的分區。對應就是HBase中的一張表。該表中包含了所有的Cuboid。

例如:以下為針對某個Cube的Segment

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

3、全量建構與增量建構

全量建構

     在全量建構中,Cube中隻存在唯一的一個Segment,該Segment沒有分割時間的概念,也就沒有起始時間和結束時間。

全量建構和增量建構各有其适用的場景,使用者可以根據自己的業務場景靈活地進行切換。

對于全量建構來說,每當需要更新Cube資料的時候,它不會區分曆史資料和新加入的資料,也就是說,在建構的時候會導入并處理所有的原始資料。

增量建構

增量建構隻會導入新Segment指定的時間區間内的原始資料,并隻對這部分原始資料進行預計算。

全量建構和增量建構的對比

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

全量建構Cube全量建構與增量建構的Cube查詢方式對比:

    • 查詢引擎隻需向存儲引擎通路單個Segment所對應的資料,無需進行Segment之間的聚合
    • 為了加強性能,單個Segment的資料也有可能被分片存儲到引擎的多個分區上,查詢引擎可能仍然需要對單個Segment不同分區的資料做進一步的聚合
  • 增量建構Cube
    • 由于不同時間的資料分布在不同的Segment之中,查詢引擎需要向存儲引擎請求讀取各個Segment的資料
    • 增量建構的Cube上的查詢會比全量建構的做更多的運作時聚合,通常來說增量建構的Cube上的查詢會比全量建構的Cube上的查詢要慢一些

對于小資料量的Cube,或者經常需要全表更新的Cube,使用全量建構需要更少的運維精力,以少量的重複計算降低生産環境中的維護複雜度。而對于大資料量的Cube,例如,對于一個包含兩年曆史資料的Cube,如果需要每天更新,那麼每天為了新資料而去重複計算過去兩年的資料就會變得非常浪費,在這種情況下需要考慮使用增量建構

4、增量建構Cube過程

1、指定分割時間列

增量建構Cube的定義必須包含一個時間次元,用來分割不同的Segment,這樣的次元稱為分割時間列(Partition Date Column)。

2、增量建構過程

  • 在進行增量建構時,将增量部分的起始時間和結束時間作為增量建構請求的一部分送出給Kylin的任務引擎
  • 任務引擎會根據起始時間和結束時間從Hive中抽取相應時間的資料,并對這部分資料做預計算處理
  • 将預計算的結果封裝成為一個新的Segment,并将相應的資訊儲存到中繼資料和存儲引擎中。一般來說,增量部分的起始時間等于Cube中最後一個Segment的結束時間。

5、增量Cube的建立-案例

準備動作

1.執行建表語句

-- 1. 建立資料庫、建立表
create database if not exists `kylin_dw`;

-- 2. 建立使用者次元表
create table `kylin_dw`.`dim_user`(
    id string,
    name string
)
row format delimited fields terminated by ',';

-- 3. 建立訂單事實表
create table `kylin_dw`.`fact_order`(
    order_id string,
    user_id string,
    price int
)
partitioned by (dt string)
row format delimited fields terminated by ',';
           

2.導入資料

load data local inpath '/export/datas/kylin_demos/data_dim_user.txt' overwrite into table `itcast_kylin_dw`.`dim_user`;
load data local inpath '/export/datas/kylin_demos/data_order_20191011.txt' overwrite into table `kylin_dw`.`fact_order` partition(dt='20191011');
load data local inpath '/export/datas/kylin_demos/data_order_20191012.txt' overwrite into table `kylin_dw`.`fact_order` partition(dt='20191012');
load data local inpath '/export/datas/kylin_demos/data_order_20191013.txt' overwrite into table `kylin_dw`.`fact_order` partition(dt='20191013');
           
建立增量Cube的過程和建立普通Cube的過程基本類似,隻是增量Cube會有一些額外的配置要求

Hive的SQL語句

​
select 
    t1.user_id,
    t2.name,
    max(t1.price)
​
from itcast_kylin_dw.fact_order t1
left join itcast_kylin_dw.dim_user t2
on t1.user_id = t2.id
group by t1.user_id,t2.name;
           

Kylin操作步驟

1、配置Model

增量建構的Cube需要指定分割時間列。

例如:将日期分區字段添加到次元列中

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

在設定中,配置分區列,并指定日期格式  

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

2.配置Cube

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

運作Cube

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

注意事項

  • 注意建構Cube時,選擇的分區時間為,起始時間(包含)、結束時間(不儲存),對應了從Hive從擷取資料源的條件
INSERT OVERWRITE TABLE `kylin_intermediate_cube_order_1582ee64_45f9_cf22_bef2_e0b455efc284` SELECT
`FACT_ORDER`.`DT` as `FACT_ORDER_DT`
,`FACT_ORDER`.`USER_ID` as `FACT_ORDER_USER_ID`
,`FACT_ORDER`.`PRICE` as `FACT_ORDER_PRICE`
 FROM `ITCAST_KYLIN_DW`.`FACT_ORDER` as `FACT_ORDER`
INNER JOIN `ITCAST_KYLIN_DW`.`DIM_USER` as `DIM_USER`
ON `FACT_ORDER`.`USER_ID` = `DIM_USER`.`ID`
WHERE 1=1 AND (`FACT_ORDER`.`DT` >= '20191011' AND `FACT_ORDER`.`DT` < '20191012');
           

檢視增量建構Cube對應的Segment

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

增量建構Cube 的時候,每個時間段 的 資料對應一個 Segment ,一個 Segement 對應一個HBase表。

二、Cube碎片管理

1、增量建構的問題

日積月累,增量建構的Cube中的Segment越來越多,該Cube的查詢性能也會越來越慢,因為需要在單點的查詢引擎中完成越來越多的運作時聚合。為了保持查詢性能:

  • 需要定期地将某些Segment合并在一起
  • 或者讓Cube根據Segment保留政策自動地淘汰那些不會再被查詢到的陳舊Segment

2、管理Cube碎片

上述案例,每天都會生成一個Segment,對應就是HBase中的一張表。增量建構的Cube每天都可能會有新的增量。這樣的Cube中最終可能包含上百個Segment,這将會導緻Kylin性能受到嚴重的影響。

  • 從執行引擎的角度來說,運作時的查詢引擎需要聚合多個Segment的結果才能傳回正确的查詢結果
  • 從存儲引擎的角度來說,大量的Segment會帶來大量的檔案,給存儲空間的多個子產品帶來巨大的壓力,例如Zookeeper、HDFS Namenode等

是以,有必要采取措施控制Cube中Segment的數量。

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

3、手動觸發合并Segment

Kylin提供了一種簡單的機制用于控制Cube中Segment的數量:合并Segments。在Web GUI中選中需要進行Segments合并的Cube

操作步驟:

1、單擊Action→Merge

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

2、選中需要合并的Segment,可以同時合并多個Segment,但是這些Segment必須是連續的

單擊送出後系統會送出一個類型為“MERGE”的建構任務,它以選中的Segment中的資料作為輸入,将這些Segment的資料合并封裝成為一個新的Segment。新的Segment的起始時間為選中的最早的Segment的起始時間,它的結束時間為選中的最晚的Segment的結束時間。

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
注意事項
  • 在MERGE類型的建構完成之前,系統将不允許送出這個Cube上任何類型的其他建構任務
  • 在MERGE建構結束之前,所有選中用來合并的Segment仍然處于可用的狀态
  • 當MERGE建構結束的時候,系統将選中合并的Segment替換為新的Segment,而被替換下的Segment等待将被垃圾回收和清理,以節省系統資源

3、删除Segment

使用WebUI删除Cube

1、disable Cube

2、點選 delete Segment,删除指定的segment

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

4、自動合并

手動維護Segment很繁瑣,人工成本很高,Kylin中是可以支援自動合并Segment。

在Cube Designer的“Refresh Settings”的頁面中有:

  • Auto Merge Thresholds
  • Retention Threshold

兩個設定項可以用來幫助管理Segment碎片。這兩項設定搭配使用這兩項設定可以大大減少對Segment進行管理的麻煩。

1、Auto Merge Thresholds

  • 允許使用者設定幾個層級的時間門檻值,層級越靠後,時間門檻值就越大
  • 每當Cube中有新的Segment狀态變為 READY的時候,會自動觸發一次系統自動合并
  • 合并政策
    • 嘗試最大一級的時間門檻值,例如:針對(7天、28天)層級的日志,先檢查能否将連續的若幹個Segment合并成為一個超過28天的大Segment
      • 如果有個别的Segment的時間長度本身已經超過28天,系統會跳過Segment
      • 如果滿足條件的連續Segment還不能夠累積超過28天,那麼系統會使用下一個層級的時間門檻值重複尋找

示例1 - 了解Kylin自動合并政策

  • 假設自動合并門檻值設定為7天、28天
  • 如果現在有A-H8個連續的Segment,它們的時間長度為28天(A)、7天(B)、1天(C)、1天(D)、1天(E)、1天(F)、1天(G)、1天(H)
  • 此時,第9個Segment I加入,時間長度為1天。

自動合并政策為:

1、Kylin判斷時候能将連續的Segment合并到28天這個門檻值,由于Segment A已經超過28天,會被排除

2、剩下的連續Segment,所有時間加一起 B + C + D + E + F + G + H + I (7 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 14) < 28天,無法滿足28天門檻值,開始嘗試7天門檻值

3、跳過A(28)、B(7)均超過7天,排除

4、剩下的連續Segment,所有時間加一起 C + D + E + F + G + H + I(1 + 1 + 1 + 1 + 1 + 1 + 1 = 7)達到7天門檻值,觸發合并,送出Merge任務。并建構一個Segment X(7天)

5、合并後,Segment為:A(28天)、B(7天)、X(7天)

6、繼續觸發檢查,A(28天)跳過,B + X(7 + 7 = 14)< 28天,不滿足第一門檻值,重新使用第二門檻值觸發

7、跳過B、X,嘗試終止

  • 一句話總結:局部相加 滿足小的門檻值合并

2、示例:配置自動合并2天的Segment

操作步驟:

1、配置自動合并門檻值為(2、3)

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

2、分别按照天建構分區Cube

3、自動觸發合并Segment建構

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

5、配置保留Segment

自動合并是将多個Segment合并為一個Segment,以達到清理碎片的目的。保留Segment則是及時清理不再使用的Segment。

在很多場景中,隻會對過去一段時間内的資料進行查詢,例如:

  • 對于某個隻顯示過去1年資料的報表
  • 支撐它的Cube其實隻需要保留過去一年類的Segment即可
  • 由于資料在Hive中已經存在備份,則無需在Kylin中備份超過一年的曆史資料

可以将Retention Threshold設定為365。每當有新的Segment狀态變為READY的時候,系統會檢查每一個Segment。如果它的結束時間距離最晚的一個Segment的結束時間已經大于等于“Retention Threshold”,那麼這個Segment将被視為無需保留。系統會自動地從Cube中删除這個Segment。

需求:

  • 配置保留Segment為2天,分别建構增量Segment,測試Segment保留情況

操作步驟:

1、在Cube中設定Retention Range為2

2、重新建構Cube

3、測試超過指定保留時間的Segment,是否被自動移除

三、使用JDBC連接配接操作Kylin

  • 要将資料以可視化方式展示出來,需要使用Kylin的JDBC方式連接配接執行SQL,擷取Kylin的執行結果
  • 使用Kylin的JDBC與JDBC操作MySQL一緻
    • jdbc url
      • jdbc:kylin://node01:7070/itcast_dw
    • 使用者名密碼:ADMIN/KYLIN

需求

  • 通過JDBC方式,查詢按照日期、區域、産品次元統計訂單總額/總數量結果

開發步驟

  • 導入驅動依賴
<dependencies>
    <!-- Kylin -->
    <dependency>
        <groupId>org.apache.kylin</groupId>
        <artifactId>kylin-jdbc</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.1-jre</version>
    </dependency>
</dependencies>
           

1、加載驅動

2、建立Connection連接配接對象

3、建構SQL語句

4、建立Statement對象,并執行executeQuery

5、列印結果

參考代碼

​
public static void main(String[] args) throws Exception {
    // 1、加載驅動
    Class.forName("org.apache.kylin.jdbc.Driver");
    // 2、建立Connection連接配接對象
    // 連接配接字元串:jdbc:kylin://ip位址:7070/項目名稱
    Connection connection = DriverManager.getConnection("jdbc:kylin://node01:7070/kylin_dw_test",
                                                        "ADMIN",
                                                        "KYLIN");

    // 3、建立Statement對象,并執行executeQuery,擷取ResultSet
    Statement statement = connection.createStatement();

    // 建構SQL和語句
    String sql = "select\n" +
        "  t1.date1,\n" +
        "  t2.regionname,\n" +
        "  productname,\n" +
        "  sum(t1.price) as total_money,\n" +
        "  sum(t1.amount) as total_amount\n" +
        "from\n" +
        "  dw_sales t1\n" +
        "inner join dim_region t2\n" +
        "on t1.regionid = t2.regionid\n" +
        "inner join dim_product t3\n" +
        "on t1.productid = t3.productid\n" +
        "group by\n" +
        "  t1.date1,\n" +
        "  t2.regionid,\n" +
        "  t2.regionname,\n" +
        "  t3.productid,\n" +
        "  t3.productname";
    ResultSet resultSet = statement.executeQuery(sql);

    // 4、列印ResultSet
    while(resultSet.next()) {
        // 4.1 擷取時間
        String date1 = resultSet.getString("date1");
        // 4.2 擷取區域名稱
        String regionname = resultSet.getString("regionname");
        // 4.3 擷取産品名稱
        String productname = resultSet.getString("productname");
        // 4.4 總金額
        String total_money = resultSet.getString("total_money");
        // 4.5 總數量
        String total_amount = resultSet.getString("total_amount");

        System.out.println(date1 + " " + regionname + " " + productname + " " + total_money + " " + total_amount);
    }

    connection.close();
}

​
           

四、Kylin Cube優化-Cuboid剪枝優化

1、為什麼要進行Cuboid剪枝優化

将以減少Cuboid數量為目的的Cuboid優化統稱為Cuboid剪枝。在沒有采取任何優化措施的情況下,Kylin會對每一種次元的組合進行預計算,每種次元的組合的預計算結果被稱為Cuboid。

  • 如果有4個次元,可能最終會有2^4 =16個Cuboid需要計算。但在實際開發中,使用者的次元數量一般遠遠大于4個。
  • 如果有10個次元,那麼沒有經過任何優化的Cube就會存在2^10 =1024個Cuboid
  • 如果有20個次元,那麼Cube中總共會存在2^20 =104 8576個Cuboid

這樣的Cuboid的數量就足以讓人想象到這樣的Cube對建構引擎、存儲引擎壓力非常巨大。是以,在建構次元數量較多的Cube時,尤其要注意Cube的

剪枝優化

Cube的剪枝優化是一種試圖減少額外空間占用的方法,這種方法的前提是不會明顯影響查詢時間。在做剪枝優化的時候,

  • 需要選擇跳過那些“多餘”的Cuboid
  • 有的Cuboid因為查詢樣式的原因永遠不會被查詢到,是以顯得多餘
  • 有的Cuboid的能力和其他Cuboid接近,是以顯得多餘

Kylin提供了一系列簡單的工具來幫助他們完成Cube的剪枝優化

2、檢查Cuboid數量

Apache Kylin提供了一個簡單的工具,檢查Cube中哪些Cuboid最終被預計算了,稱這些Cuboid為被物化的Cuboid,該工具還能給出每個Cuboid所占空間的估計值。由于該工具需要在對資料進行一定階段的處理之後才能估算Cuboid的大小,是以一般來說隻能在Cube建構完畢之後再使用該工具。

使用如下的指令行工具去檢查這個Cube中的Cuboid狀态:

bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader CUBE_NAME 
# CUBE_NAME 想要檢視的Cube的名字
           

示例:

​
bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader cube_order 
​
============================================================================
Statistics of cube_order[20191011000000_20191015000000]
​
Cube statistics hll precision: 14
Total cuboids: 3
Total estimated rows: 20
Total estimated size(MB): 1.02996826171875E-4
Sampling percentage:  100
Mapper overlap ratio: 0.0
Mapper number: 0
Length of dimension KYLIN_DW.FACT_ORDER.DT is 1
Length of dimension KYLIN_DW.FACT_ORDER.USER_ID is 1
|---- Cuboid 11, est row: 12, est MB: 0
    |---- Cuboid 01, est row: 4, est MB: 0, shrink: 33.33%
    |---- Cuboid 10, est row: 4, est MB: 0, shrink: 33.33%
----------------------------------------------------------------------------

​
           

輸出結果分析:

Cube statistics hll precision: 14
Total cuboids: 3
Total estimated rows: 20
Total estimated size(MB): 1.02996826171875E-4
Sampling percentage:  100
Mapper overlap ratio: 0.0
Mapper number: 0
           
  • 估計Cuboid大小的精度(Hll Precision)
  • 總共的Cuboid數量
  • Segment的總行數估計
  • Segment的大小估計,Segment的大小決定mapper、reducer的數量、資料分片數量等
|---- Cuboid 11, est row: 12, est MB: 0
    |---- Cuboid 01, est row: 4, est MB: 0, shrink: 33.33%
    |---- Cuboid 10, est row: 4, est MB: 0, shrink: 33.33%
           
  • 所有的Cuboid及它的分析結果都以樹狀的形式列印了出來
  • 在這棵樹中,每個節點代表一個Cuboid,每個Cuboid都由一連串1或0的數字組成
  • 數字串的長度等于有效次元的數量,從左到右的每個數字依次代表Rowkeys設定中的各個次元。如果數字為0,則代表這個Cuboid中不存在相應的次元;如果數字為1,則代表這個Cuboid中存在相應的次元
  • 除了最頂端的Cuboid之外,每個Cuboid都有一個父親Cuboid,且都比父親Cuboid少了一個“1”。其意義是這個Cuboid就是由它的父親節點減少一個次元聚合而來的
  • 最頂端的Cuboid稱為Base Cuboid,它直接由源資料計算而來。Base Cuboid中包含所有的次元,是以它的數字串中所有的數字均為1
  • 每行Cuboid的輸出中除了0和1的數字串以外,後面還有每個Cuboid的具體資訊,包括該Cuboid行數的估計值、該Cuboid大小的估計值,以及這個Cuboid的行數與父親節點的對比(Shrink值)
  • 所有Cuboid行數的估計值之和應該等于Segment的行數估計值,所有Cuboid的大小估計值應該等于該Segment的大小估計值。每個Cuboid都是在它的父親節點的基礎上進一步聚合而成的

3、檢查Cube大小

    在Web GUI的Model頁面選擇一個READY狀态的Cube,當我們把光标移到該Cube的Cube Size列時,Web GUI會提示Cube的源資料大小,以及目前Cube的大小除以源資料大小的比例,稱為

膨脹率(Expansion Rate)

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

一般來說,Cube的膨脹率應該在0%~1000%之間,如果一個Cube的膨脹率超過1000%,那麼應當開始挖掘其中的原因。通常,膨脹率高有以下幾個方面的原因:

  • Cube中的次元數量較多,且沒有進行很好的Cuboid剪枝優化,導緻Cuboid數量極多
  • Cube中存在較高基數的次元,導緻包含這類次元的每一個Cuboid占用的空間都很大,這些Cuboid累積造成整體Cube體積變大
  • 存在比較占用空間的度量,例如Count Distinct,是以需要在Cuboid的每一行中都為其儲存一個較大度量資料,最壞的情況将會導緻Cuboid中每一行都有數十KB,進而造成整個Cube的體積變大。

對于Cube膨脹率居高不下的情況,需要結合實際資料進行分析,優化。

4、使用衍生次元

示例:

  • 有兩張表 使用者次元表(dim_user)、訂單事實表(fact_order),要根據各個次元建立MOLAP立方體

使用者次元表(dim_user)

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

訂單事實表(fact_order)

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

問題:

  •        生成Cube時,如果指定次元表中的:姓名、出生年份、政治面貌、職業、性别、民族、省份、市、區等次元生成Cube,這些次元互相組合,會造成較大的Cube膨脹率

使用衍生次元用于在有效次元内将次元表上的非主鍵次元排除掉,并使用次元表的主鍵(其實是事實表上相應的外鍵)來替代它們。Kylin會在底層記錄次元表主鍵與次元表其他次元之間的映射關系,以便在查詢時能夠動态地将次元表的主鍵“翻譯”成這些非主鍵次元,并進行 實時聚合。

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

建立Cube的時候,這些次元如果指定為衍生次元,Kylin将會排除這些次元,而是使用次元表的主鍵來代替它們建立Cuboid。後續查詢的時候,再基于主鍵的聚合結果,再進行一次聚合。

  • 優化效果:次元表的N個次元組合成的cuboid個數會從2^N降為2。
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化
  •   隻把normal 類型的次元列生成為 Cuboid

不适用的場景:

  • 如果從次元表主鍵到某個次元表次元所需要的聚合工作量非常大,此時作為一個普通的次元聚合更合适,否則會影響Kylin的查詢性能

美團“次元爆炸”問題在實踐中是可解的

提到MOLAP Cube方案,很多沒接觸過Kylin的人會擔心“次元爆炸”的問題,即每增加一個次元,由于次元組合數翻倍,Cube的計算和存儲量也會成倍增長。我們起初其實也有同樣的擔心,但調研和使用Kylin一陣子後發現,這個問題在實踐中并沒有想象的嚴重。這主要是因為

  1. Kylin支援Partial Cube,不需要對所有次元組合都進行預計算
  2. 實際業務中,次元之間往往存在衍生關系,而Kylin可以把衍生次元的計算從預計算推遲到查詢處理階段
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

以事實表上的衍生次元為例,我們業務中的很多元度都是(ID, NAME)成對出現的。查詢時需要對ID列進行過濾,但顯示時隻需要取對應的NAME列。如果把這兩列都作為次元,次元個數會翻倍。而在Kylin中,可以把NAME作為ID列的extendedcolumn名額,這樣Cube中的次元個數就減半了。

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

下面分享一些我們線上Cube的統計資料。

Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

可以看到,采用衍生次元後,90%的場景可以把Cube中的次元個數(Rowkey列數)控制在20個以内。名額個數呈現長尾分布,小于10個名額的Cube是最多的,不過也有近一半的Cube名額數超過20。總共有382個去重名額,占到了總名額數的10%,絕大多數都是精确去重名額。49%的Cube膨脹率小于100%,即Cube存儲量不超過上遊Hive表。68%的Cube能夠在1小時内完成建構,92%在2小時内完成建構。

5、聚合組

  • 聚合組(Aggregation Group)是一種更強大的剪枝工具
  • 聚合組假設一個Cube的 所有次元 均可以根據業務需求劃分成若幹組
  • 同一個組内的次元更可能同時被同一個查詢用到,每個分組的次元集合均是 Cube 所有次元的一個子集
  • 不同的分組各自擁有一套次元集合,它們可能與其他分組有相同的次元,也可能沒有相同的次元
  • 每個分組各自獨立地根據自身的規則貢獻出一批需要被物化的Cuboid,所有分組貢獻的Cuboid的并集就成為了目前Cube中所有需要物化的Cuboid的集合
  • 不同的分組有可能會貢獻出相同的Cuboid,建構引擎會察覺到這點,并且保證每一個Cuboid無論在多少個分組中出現,它都隻會被物化一次
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化

對于每個分組内部的次元,使用者可以使用如下三種可選的方式定義它們之間的關系,具體如下:

  • 強制次元(Mandatory)
    • 如果一個次元被定義為強制次元,那麼這個分組産生的所有Cuboid中每一個Cuboid都會包含該次元。所有cuboid必須包含的次元,不會計算不包含強制次元的cuboid
    • 每個分組中都可以有0個、1個或多個強制次元
    • 如果根據這個分組的業務邏輯,則相關的查詢一定會在過濾條件或分組條件中,是以可以在該分組中把該次元設定為強制次元
    • 适用場景
      • 可以将确定在查詢時一定會使用的次元設為強制次元。例如,時間次元。
    • 優化效果
      • 将一個次元設為強制次元,則cuboid個數直接減半
  • 層級次元(Hierarchy)
    • 每個層級包含兩個或更多個次元
    • 假設一個層級中包含D1,D2…Dn這n個次元,那麼在該分組産生的任何Cuboid中,這n個次元隻會以(),(D1),(D1,D2)…(D1,D2…Dn)這n+1種形式中的一種出現
    • 每個分組中可以有0個、1個或多個層級,不同的層級之間不應當有共享的次元
    • 如果根據這個分組的業務邏輯,則多個次元直接存在層級關系,是以可以在該分組中把這些次元設定為層級次元
    • 使用場景
      • 年,月,日;國家,省份,城市這類具有層次關系的次元
    • 優化效果
      • 将N個次元設定為層次次元,則這N個次元組合成的cuboid個數會從2^n -1 減少到N
  • 聯合次元(Joint)
    • 每個聯合中包含兩個或更多個次元,如果某些列形成一個聯合,那麼在該分組産生的任何Cuboid中,這些聯合次元要麼一起出現,要麼都不出現
    • 每個分組中可以有0個或多個聯合,但是不同的聯合之間不應當有共享的次元(否則它們可以合并成一個聯合)。如果根據這個分組的業務邏輯,多個次元在查詢中總是同時出現,則可以在該分組中把這些次元設定為聯合次元
    • 适用場景
      • 可以将确定在查詢時一定會同時使用的幾個次元設為一個聯合次元
    • 優化效果
      • 将N個次元設定為聯合次元,則這N個次元組合成的cuboid個數會從2^n-1減少到1
Kylin 學習筆記(二)-----Kylin增量建構入門、Cube碎片管理、JDBC連接配接、Cube簡單優化