Kylin(二):Cube构建原理和优化、BI工具集成

一、Cube构建原理

1.1 Cube构建流程

① 创建中间表
在这里插入图片描述
② 将中间表的数据均匀分配到不同的文件

通常将1百万条数据分到同一文件,因为1百万条数据通常小于HDFSBlock Szie128M。
在这里插入图片描述
③ 创建维度字典表
在这里插入图片描述
④ 构建cube
在这里插入图片描述
⑤ 构建Hbase K-V

Cuboid id+维度值组成了HBaseRowKey,这样大大减少了数据量,Cuboid id每个位即各维度是否存在,存在为1,不存在为0。
在这里插入图片描述
⑥ 将cube data转成HFile格式并导入HBase
在这里插入图片描述

1.2 Cube构建算法

1.2.1 逐层构建算法(layer)

在这里插入图片描述
我们知道,一个N维的Cube,是由1个N维子立方体、NN-1维子立方体、N*(N-1)/2N-2维子立方体、…、N个1维子立方体和1个0维子立方体构成,总共有2^N个子立方体组成,在逐层算法中,按维度数逐层减少来计算,每个层级的计算(除了第一层,它是从原始数据聚合而来),是基于它上一层级的结果来计算的。比如,[Group by A, B]的结果,可以基于[Group by A, B, C]的结果,通过去掉C后聚合得来的;这样可以减少重复计算;当 0维度Cuboid计算出来的时候,整个Cube的计算也就完成了。

每一轮的计算都是一个MapReduce任务,且串行执行;一个N维的Cube,至少需要NMapReduce Job
在这里插入图片描述
算法优点:

  1. 此算法充分利用了MapReduce的优点,处理了中间复杂的排序和shuffle工作,故而算法代码清晰简单,易于维护;
  2. 受益于Hadoop的日趋成熟,此算法非常稳定,即便是集群资源紧张时,也能保证最终能够完成。

算法缺点:

  1. Cube有比较多维度的时候,所需要的MapReduce任务也相应增加;由于Hadoop的任务调度需要耗费额外资源,特别是集群较庞大的时候,反复递交任务造成的额外开销会相当可观;
  2. 由于Mapper逻辑中并未进行聚合操作,所以每轮MRshuffle工作量都很大,导致效率低下。
  3. HDFS的读写操作较多:由于每一层计算的输出会用做下一层计算的输入,这些Key-Value需要写到HDFS上;当所有计算都完成后,Kylin还需要额外的一轮任务将这些文件转成HBaseHFile格式,以导入到HBase中去;

总体而言,该算法的效率较低,尤其是当Cube维度数较大的时候。

1.2.2 快速构建算法(inmem)

在这里插入图片描述
也被称作逐段(By Segment) 或逐块(By Split) 算法,从1.5.x开始引入该算法,该算法的主要思想是,每个Mapper将其所分配到的数据块,计算成一个完整的小Cube段(包含所有Cuboid)。每个Mapper将计算完的Cube段输出给Reducer做合并,生成大Cube,也就是最终结果。如图所示解释了此流程。
在这里插入图片描述
与旧算法相比,快速算法主要有两点不同:

  1. Mapper会利用内存做预聚合,算出所有组合;Mapper输出的每个Key都是不同的,这样会减少输出到Hadoop MapReduce的数据量,Combiner也不再需要;
  2. 一轮MapReduce便会完成所有层次的计算,减少Hadoop任务的调配。

二、Cube构建优化

从之前章节的介绍可以知道,在没有采取任何优化措施的情况下,Kylin会对每一种维度的组合进行预计算,每种维度的组合的预计算结果被称为Cuboid。假设有4个维度,我们最终会有2^4 =16个Cuboid需要计算。

但在现实情况中,用户的维度数量一般远远大于4个。假设用户有10 个维度,那么没有经过任何优化的Cube就会存在2^10 =1024个Cuboid;而如果用户有20个维度,那么Cube中总共会存在2^20 =1048576个Cuboid。虽然每个Cuboid的大小存在很大的差异,但是单单想到Cuboid的数量就足以让人想象到这样的Cube对构建引擎、存储引擎来说压力有多么巨大。因此,在构建维度数量较多的Cube时,尤其要注意Cube的剪枝优化(即减少Cuboid的生成)。

2.1 使用衍生维度(derived dimension)

衍生维度用于在有效维度内将维度表上的非主键维度排除掉,并使用维度表的主键(其实是事实表上相应的外键)来替代它们。Kylin会在底层记录维度表主键与维度表其他维度之间的映射关系,以便在查询时能够动态地将维度表的主键“翻译”成这些非主键维度,并进行实时聚合。
在这里插入图片描述
虽然衍生维度具有非常大的吸引力,但这也并不是说所有维度表上的维度都得变成衍生维度,如果从维度表主键到某个维度表维度所需要的聚合工作量非常大,则不建议使用衍生维度。
在这里插入图片描述

2.2 使用聚合组(Aggregation group)

聚合组(Aggregation Group)是一种强大的剪枝工具。聚合组假设一个Cube的所有维度均可以根据业务需求划分成若干组(当然也可以是一个组),由于同一个组内的维度更可能同时被同一个查询用到,因此会表现出更加紧密的内在关联。每个分组的维度集合均是Cube所有维度的一个子集,不同的分组各自拥有一套维度集合,它们可能与其他分组有相同的维度,也可能没有相同的维度。每个分组各自独立地根据自身的规则贡献出一批需要被物化的Cuboid,所有分组贡献的Cuboid的并集就成为了当前Cube中所有需要物化的Cuboid的集合。不同的分组有可能会贡献出相同的Cuboid,构建引擎会察觉到这点,并且保证每一个Cuboid无论在多少个分组中出现,它都只会被物化一次。

对于每个分组内部的维度,用户可以使用如下三种可选的方式定义,它们之间的关系,具体如下:

① 强制维度(Mandatory

如果一个维度被定义为强制维度,那么这个分组产生的所有CuboId中每一个CuboId都会包含该维度。每个分组中都可以有0个、1个或多个强制维度。如果根据这个分组的业务逻辑,则相关的查询一定会在过滤条件或分组条件中,因此可以在该分组中把该维度设置为强制维度。
在这里插入图片描述
② 层级维度(Hierarchy

每个层级包含两个或更多个维度。假设一个层级中包含D1D2Dnn个维度,那么在该分组产生的任何CuboId中, 这n个维度只会以()(D1)(D1,D2)(D1,D2…Dn)n+1种形式中的一种出现。每个分组中可以有0个、1个或多个层级,不同的层级之间不应当有共享的维度。如果根据这个分组的业务逻辑,则多个维度直接存在层级关系,因此可以在该分组中把这些维度设置为层级维度。
在这里插入图片描述
③ 联合维度(Joint

每个联合中包含两个或更多个维度,如果某些列形成一个联合,那么在该分组产生的任何CuboId中,这些联合维度要么一起出现,要么都不出现。每个分组中可以有0个或多个联合,但是不同的联合之间不应当有共享的维度(否则它们可以合并成一个联合)。如果根据这个分组的业务逻辑,多个维度在查询中总是同时出现,则可以在该分组中把这些维度设置为联合维度。
在这里插入图片描述
这些操作可以在Cube DesignerAdvanced Setting中的Aggregation Groups区域完成,如下图所示:
在这里插入图片描述
聚合组的设计非常灵活,甚至可以用来描述一些极端的设计。假设我们的业务需求非常单一,只需要某些特定的CuboId,那么可以创建多个聚合组,每个聚合组代表一个CuboId。具体的方法是在聚合组中先包含某个CuboId所需的所有维度,然后把这些维度都设置为强制维度。这样当前的聚合组就只能产生我们想要的那一个CuboId了。

再比如,有的时候我们的Cube中有一些基数非常大的维度,如果不做特殊处理,它就会和其他的维度进行各种组合,从而产生一大堆包含它的CuboId。包含高基数维度的CuboId在行数和体积上往往非常庞大,这会导致整个Cube的膨胀率变大。如果根据业务需求知道这个高基数的维度只会与若干个维度(而不是所有维度)同时被查询到,那么就可以通过聚合组对这个高基数维度做一定的“隔离”。我们把这个高基数的维度放入一个单独的聚合组,再把所有可能会与这个高基数维度一起被查询到的其他维度也放进来。这样,这个高基数的维度就被“隔离”在一个聚合组中了,所有不会与它一起被查询到的维度都没有和它一起出现在任何一个分组中,因此也就不会有多余的CuboId产生。这点也大大减少了包含该高基数维度的CuboId的数量,可以有效地控制Cube的膨胀率。

2.3 Row Key优化

Kylin会把所有的维度按照顺序组合成一个完整的RowKey,并且按照这个RowKey升序排列CuboId中所有的行。设计良好的RowKey将更有效地完成数据的查询过滤和定位,减少IO次数,提高查询速度,维度在RowKey中的次序,对查询性能有显著的影响。

RowKey的设计原则如下:

① 被用作where过滤的维度放在前边
在这里插入图片描述

② 基数大的维度放在基数小的维度前边
在这里插入图片描述

2.4 并发粒度优化

Segment中某一个Cuboid的大小超出一定的阈值时,系统会将该Cuboid的数据分片到多个分区中,以实现Cuboid数据读取的并行化,从而优化Cube的查询速度。具体的实现方式如下:构建引擎根据Segment估计的大小,以及参数kylin.hbase.region.cut的设置决定Segment在存储引擎中总共需要几个分区来存储,如果存储引擎是HBase,那么分区的数量就对应于HBase中的Region数量。kylin.hbase.region.cut的默认值是5.0,单位是GB,也就是说对于一个大小估计是50GBSegment,构建引擎会给它分配10个分区。用户还可以通过设置kylin.hbase.region.count.min(默认为1)和kylin.hbase.region.count.max(默认为500)两个配置来决定每个Segment最少或最多被划分成多少个分区。
在这里插入图片描述
由于每个Cube的并发粒度控制不尽相同,因此建议在Cube DesignerConfiguration Overwrites(上图所示)中为每个Cube量身定制控制并发粒度的参数。假设将把当前Cubekylin.hbase.region.count.min设置为2,kylin.hbase.region.count.max设置为100。这样无论Segment的大小如何变化,它的分区数量最小都不会低于2,最大都不会超过100。相应地,这个Segment背后的存储引擎(HBase)为了存储这个Segment,也不会使用小于两个或超过100个的分区。我们还调整了默认的kylin.hbase.region.cut,这样50GBSegment基本上会被分配到50个分区,相比默认设置,我们的Cuboid可能最多会获得5倍的并发量。

三、BI工具集成

可以与Kylin结合使用的可视化工具很多,例如:

  • ODBC:与TableauExcelPowerBI等工具集成;
  • JDBC:与SaikuBIRTJava工具集成;
  • RestAPI:与JavaScriptWeb网页集成;

Kylin开发团队还贡献了Zepplin的插件,也可以使用Zepplin来访问Kylin服务。

3.1 JDBC

引入依赖:

<dependency>
    <groupId>org.apache.kylin</groupId>
    <artifactId>kylin-jdbc</artifactId>
    <version>2.5.1</version>
</dependency>

代码:

public class KylinTest {

    //驱动
    public static final String KYLIN_DRIVER = "org.apache.kylin.jdbc.Driver";
    //URL
    public static final String KYLIN_URL = "jdbc:kylin://hadoop100:7070/FirstProject";
    //用户名
    public static final String KYLIN_USER = "admin";
    //密码
    public static final String KYLIN_PASSWORD = "KYLIN";

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //加载驱动
        Class.forName(KYLIN_DRIVER);
        //获取连接
        Connection con = DriverManager.getConnection(KYLIN_URL, KYLIN_USER, KYLIN_PASSWORD);
        //预编译sql
        PreparedStatement ps = con.prepareStatement("SELECT SUM(SAL) FROM EMP GROUP BY DEPTNO");
        //执行查询
        ResultSet result = ps.executeQuery();
        while (result.next()) {
            System.out.println(result.getInt(1));
        }
    }
}

结果:
在这里插入图片描述

3.2 Zepplin

Zepplin安装与启动

解压:

[root@hadoop100 sorfware]# tar -zxvf zeppelin-0.8.0-bin-all.tgz -C /opt/module/

启动

[root@hadoop100 zeppelin-0.8.0]#  bin/zeppelin-daemon.sh start

访问http://hadoop102:8080查看web页面

② 配置Zepplin支持Kylin

点击右上角anonymous选择Interpreter
在这里插入图片描述
搜索Kylin插件并修改相应的配置并保存:
在这里插入图片描述
③ 案例实操

点击Notebook创建新的note
在这里插入图片描述在这里插入图片描述
执行查询:
在这里插入图片描述
其他图表格式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38697437/article/details/107189460