1 前言

在使用Kylin的时候,最重要的一步就是创建cube的模型定义,即指定度量和维度以及一些附加信息,然后对cube进行build,当然我们也可以根据原始表中的某一个string字段(这个字段的格式必须是日期格式,表示日期的含义)设定分区字段,这样一个cube就可以进行多次build,每一次的build会生成一个segment,每一个segment对应着一个时间区间的cube,这些segment的时间区间是连续并且不重合的,对于拥有多个segment的cube可以执行merge,相当于将一个时间区间内部的segment合并成一个。下面开始分析cube的build过程。

2 Cube示例

以手机销售为例,表SALE记录各手机品牌在各个国家,每年的销售情况。表PHONE是手机品牌,表COUNTRY是国家列表,两表通过外键与SALE表相关联。这三张表就构成星型模型,其中SALE是事实表,PHONE、COUNTRY是维度表。

现在需要知道各品牌手机于2010-2012年,在中国的总销量,那么查询sql为:

SELECT b.`name`, c.`NAME`, SUM(a.count)
FROM SALE AS a
LEFT JOIN PHONE AS b ON a.`pId`=b.`id`
LEFT JOIN COUNTRY AS c ON a.`cId`=c.`id`
WHERE a.`time` >= 2010 AND a.`time` <= 2012 AND c.`NAME` = "中国"
GROUP BY b.`NAME`

其中时间(time), 手机品牌(b.name,后文用phone代替),国家(c.name,后文用country代替)是维度,而销售数量(a.count)是度量。手机品牌的个数可用于表示手机品牌列的基度。各手机品牌在各年各个国家的销量可作为一个cuboid,所有的cuboid组成一个cube,如下图所示:

上图展示了有3个维度的cube,每个小立方体代表一个cuboid,其中存储的是度量列聚合后的结果,比如苹果在中国2010年的销量就是一个cuboid。

3 入口介绍

在kylin的web页面上创建完成一个cube之后可以点击action下拉框执行build或者merge操作,这两个操作都会调用cube的rebuild接口,调用的参数包括:

  1. cube名,用于唯一标识一个cube,在当前的kylin版本中cube名是全局唯一的,而不是每一个project下唯一的;
  2. 本次构建的startTime和endTime,这两个时间区间标识本次构建的segment的数据源只选择这个时间范围内的数据;对于BUILD操作而言,startTime是不需要的,因为它总是会选择最后一个segment的结束时间作为当前segment的起始时间。
  3. buildType标识着操作的类型,可以是”BUILD”、”MERGE”和”REFRESH”。

4 构建Cube过程

Kylin中Cube的Build过程,是将所有的维度组合事先计算,存储于HBase中,以空间换时间,HTable对应的RowKey,就是各种维度组合,指标存在Column中,这样,将不同维度组合查询SQL,转换成基于RowKey的范围扫描,然后对指标进行汇总计算,以实现快速分析查询。整个过程如下图所示:

主要的步骤可以按照顺序分为几个阶段:

  1. 根据用户的cube信息计算出多个cuboid文件;
  2. 根据cuboid文件生成htable;
  3. 更新cube信息;
  4. 回收临时文件。

    每一个阶段操作的输入都需要依赖于上一步的输出,所以这些操作全是顺序执行的。下面对这几个阶段的内容细分为11步具体讲解一下:

4.1 创建Hive事实表中间表(Create Intermediate Flat Hive Table)

这一步的操作会新创建一个hive外部表,然后再根据cube中定义的星状模型,查询出维度和度量的值插入到新创建的表中,这个表是一个外部表,表的数据文件(存储在HDFS)作为下一个子任务的输入。

4.2 重新分配中间表(Redistribute Flat Hive Table)

在前面步骤,hive会在HDFS文件夹中生成数据文件,一些文件非常大,一些有些小,甚至是空的。文件分布不平衡会导致随后的MR作业不平衡:一些mappers作业很快执行完毕,但其它的则非常缓慢。为了平衡作业,kylin增加这一步“重新分配”数据。首先,kylin获取到这中间表的行数,然后根据行数的数量,它会重新分配文件需要的数据量。默认情况下,kylin分配每100万行一个文件。

4.3 提取事实表不同列值 (Extract Fact Table Distinct Columns)

在这一步是根据上一步生成的hive中间表计算出每一个出现在事实表中的维度列的distinct值,并写入到文件中,它是启动一个MR任务完成的,它关联的表就是上一步创建的临时表,如果某一个维度列的distinct值比较大,那么可能导致MR任务执行过程中的OOM。

4.4 创建维度字典(Build Dimension Dictionary)

这一步是根据上一步生成的distinct column文件和维度表计算出所有维度的子典信息,并以字典树的方式压缩编码,生成维度字典,子典是为了节约存储而设计的。

每一个cuboid的成员是一个key-value形式存储在hbase中,key是维度成员的组合,但是一般情况下维度是一些字符串之类的值(例如商品名),所以可以通过将每一个维度值转换成唯一整数而减少内存占用,在从hbase查找出对应的key之后再根据子典获取真正的成员值。

4.5 保存Cuboid的统计信息(Save Cuboid Statistics)

计算和统计所有的维度组合,并保存,其中,每一种维度组合,称为一个Cuboid。理论上来说,一个N维的Cube,便有2的N次方种维度组合,参考网上的一个例子,一个Cube包含time, item, location, supplier四个维度,那么组合(Cuboid)便有16种:

4.6 创建HTable

创建一个HTable的时候还需要考虑一下几个事情:

  1. 列簇的设置。
  2. 每一个列簇的压缩方式。
  3. 部署coprocessor。
  4. HTable中每一个region的大小。

    在这一步中,列簇的设置是根据用户创建cube时候设置的,在HBase中存储的数据key是维度成员的组合,value是对应聚合函数的结果,列簇针对的是value的,一般情况下在创建cube的时候只会设置一个列簇,该列包含所有的聚合函数的结果;

    在创建HTable时默认使用LZO压缩,如果不支持LZO则不进行压缩,在后面kylin的版本中支持更多的压缩方式;

    kylin强依赖于HBase的coprocessor,所以需要在创建HTable为该表部署coprocessor,这个文件会首先上传到HBase所在的HDFS上,然后在表的元信息中关联,这一步很容易出现错误,例如coprocessor找不到了就会导致整个regionServer无法启动,所以需要特别小心;region的划分已经在上一步确定了,所以这里不存在动态扩展的情况,所以kylin创建HTable使用的接口如下:

    public void createTable(final HTableDescriptor desc , byte [][] splitKeys)

4.7 用Spark引擎构建Cube(Build Cube with Spark)

在Kylin的Cube模型中,每一个cube是由多个cuboid组成的,理论上有N个普通维度的cube可以是由2的N次方个cuboid组成的,那么我们可以计算出最底层的cuboid,也就是包含全部维度的cuboid(相当于执行一个group by全部维度列的查询),然后在根据最底层的cuboid一层一层的向上计算,直到计算出最顶层的cuboid(相当于执行了一个不带group by的查询),其实这个阶段kylin的执行原理就是这个样子的,不过它需要将这些抽象成mapreduce模型,提交Spark作业执行。

使用Spark,生成每一种维度组合(Cuboid)的数据。

Build Base Cuboid Data;

Build N-Dimension Cuboid Data : 7-Dimension;

Build N-Dimension Cuboid Data : 6-Dimension;

……

Build N-Dimension Cuboid Data : 2-Dimension;

Build Cube。

4.8 将Cuboid数据转换成HFile(Convert Cuboid Data to HFile)

创建完了HTable之后一般会通过插入接口将数据插入到表中,但是由于cuboid中的数据量巨大,频繁的插入会对Hbase的性能有非常大的影响,所以kylin采取了首先将cuboid文件转换成HTable格式的Hfile文件,然后在通过bulkLoad的方式将文件和HTable进行关联,这样可以大大降低Hbase的负载,这个过程通过一个MR任务完成。

4.9 导HFile入HBase表(Load HFile to HBase Table)

将HFile文件load到HTable中,这一步完全依赖于HBase的工具。这一步完成之后,数据已经存储到HBase中了,key的格式由cuboid编号+每一个成员在字典树的id组成,value可能保存在多个列组里,包含在原始数据中按照这几个成员进行GROUP BY计算出的度量的值。

4.10 更新Cube信息(Update Cube Info)

更新cube的状态,其中需要更新的包括cube是否可用、以及本次构建的数据统计,包括构建完成的时间,输入的record数目,输入数据的大小,保存到Hbase中数据的大小等,并将这些信息持久到元数据库中。

4.11 清理Hive中间表(Hive Cleanup)

这一步是否成功对正确性不会有任何影响,因为经过上一步之后这个segment就可以在这个cube中被查找到了,但是在整个执行过程中产生了很多的垃圾文件,其中包括:

  1. 临时的hive表;
  2. 因为hive表是一个外部表,存储该表的文件也需要额外删除;
  3. fact distinct这一步将数据写入到HDFS上为建立子典做准备,这时候也可以删除了;
  4. rowKey统计的时候会生成一个文件,此时可以删除;
  5. 生成HFile时文件存储的路径和hbase真正存储的路径不同,虽然load是一个remove操作,但是上层的目录还是存在的,也需要删除。

至此整个Build过程结束。

Kylin构建Cube过程详解的更多相关文章

  1. ping命令执行过程详解

    [TOC] ping命令执行过程详解 机器A ping 机器B 同一网段 ping通知系统建立一个固定格式的ICMP请求数据包 ICMP协议打包这个数据包和机器B的IP地址转交给IP协议层(一组后台运 ...

  2. Cordova 打包 Android release app 过程详解

    Cordova 打包 Android release app 过程详解 时间 -- :: SegmentFault 原文 https://segmentfault.com/a/119000000517 ...

  3. eclipse里面构建maven项目详解(转载)

    本文来源于:http://my.oschina.net/u/1540325/blog/548530 eclipse里面构建maven项目详解 1       环境安装及分配 Maven是基于项目对象模 ...

  4. cegui-0.8.2编译过程详解

    cegui 编译过程详解(cegui-0.8.2) cegui配置整了好长时间了,在一位大牛帮助下终于搞定了,网上的教程大多是老版本的,cegui-0.8.2版的配置寥寥无几,现在总结一下,献给正在纠 ...

  5. linux内核剖析(零)linux系统启动过程详解-开机加电后发生了什么

    本文参考了如下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详解linux系统的启动过程及系统初 ...

  6. kylin构建cube优化

    前言 下面通过对kylin构建cube流程的分析来介绍cube优化思路. 创建hive中间表 kylin会在cube构建的第一步先构建一张hive的中间表,该表关联了所有的事实表和维度表,也就是一张宽 ...

  7. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  8. 【elasticsearch】搜索过程详解

    elasticsearch 搜索过程详解 本文基于elasticsearch8.1.在es搜索中,经常会使用索引+星号,采用时间戳来进行搜索,比如aaaa-*在es中是怎么处理这类请求的呢?是对匹配的 ...

  9. UBOOT编译--- make xxx_deconfig过程详解(一)

    make xxx_deconfig过程详解 1. 前言 2. 概述 3. build变量的定义 4. 目标%config的定义 4.1 依赖 scripts_basic 4.1.1 语句$(if $ ...

随机推荐

  1. 深度递归必须知道的尾调用(Lambda)

    引导语 本文从一个递归栈溢出说起,像大家介绍一下如何使用尾调用解决这个问题,以及尾调用的原理,最后还提供一个解决方案的工具类,大家可以在工作中放心用起来. 递归-发现栈溢出 现在我们有个需求,需要计算 ...

  2. WPF 字体图标样式

    1.在网上下载Font ICO 字体字体压缩包 Font Awesome 矢量图标库    2.下载到的压缩包,解压后获得图标字体文件        3.然后把字体文件夹拷贝到项目中,目录为(/fon ...

  3. 基于 APIGateway 打造生产级别的 Knative 服务

    作者 | 阿里云智能事业群高级开发工程师  元毅 导读:在实际应用中,通过 APIGateway(即 API 网关),可以为内部服务提供保护.提供统一的鉴权管理.限流.监控等能力,开发人员只需要关注内 ...

  4. 使用Elasticsearch7 java api实现pdf全文检索

    前提:pdf的内容是文字形式而不是图片形式! 一.方法 Elasticsearch实现pdf的全文检索,原理是将pdf转换为Base64,然后提取pdf的文字内容然后将其存储起来. Elasticse ...

  5. Sublime运行C++程序教程

    前言 传说sublime是全球最好的编辑器,可是只是编辑器啊!!!如果要运行,对于我们这些蒟蒻来说,不得不去使用DEV_C++.我们总是幻想能让sublime变成一个轻量级IDE,那该多好啊!!! 那 ...

  6. 英文写作report

    Writting Attached Files   Maybe you might want to get familiar about how to write the Final report. ...

  7. Go pprof性能调优

    在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 profiling 的库,这篇文章 ...

  8. docker java环境 直接做成镜像 跑自己的java包

    yum install docker #基于阿里源 可以直接下载 systemctl restart docker ifconfig  #出现 docker0  说明环境部署成功 docker ver ...

  9. FreeSql (十)更新数据

    FreeSql支持丰富的更新数据方法,支持单条或批量更新,在特定的数据库执行还可以返回更新后的记录值. var connstr = "Data Source=127.0.0.1;Port=3 ...

  10. spring aop 之链式调用

    关关雎鸠,在河之洲.窈窕淑女,君子好逑. 概述 AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横 ...