kylin基本概念和原理

kylin是用于DW/BI的一种OLAP工具,满足多维环境下的特定查询。

术语


  • 维度(Dimension)

    一组属性,提供结构化的标签信息,一般作为报表的坐标轴。

  • 度量(Measure)

    一类可以进行聚合分析的特殊维度,聚合后的结果称为指标。

  • 事实表(Fact Table)

    数据仓库中的中央表,用于描述业务内特定事件的数据。

  • 维度表(Lookup Table)

    维度属性的集合,人们观察数据的特定角度。

  • 基度

    指数据表中某一列数据去重后的元素个数。

  • 星型模型(Star Schema)

    一种多维的数据关系,由一张事实表和一组维度表组成。

  • cuboid

    某一维度组合下,度量聚合后的结果集合。

  • 数据立方体(cube)

    一组用于分析数据的相关度量值和维度,是所有cuboid的集合,作为存储和分析的基本单位。

示例


以手机销售为例,表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。

当数据量比较少时,可以直接使用RDBMS执行sql,在较短时间内得到结果,但对于大数据量,比如5000万条,RDBMS的性能就满足不了要求了,需要使用别的查询方案,如MPP,Hive。而kylin给我们提供了另外一个思路——预计算,即空间换时间,列出用户所有可能的查询sql,提前处理得到查询结果,并持久化到数据库中,在实际查询时,可复用之前计算的结果,速度可以达到毫秒级别。当然,用户的查询sql是多种多样,无法穷尽的,因此kylin假设用户查询局限于针对不同的维度组合,得到有限个指标的聚合结果。在实际生产中,这个假设符合一般的用户使用场景,所以,kylin仅遍历所有可能的维度组合,求得对应的cuboid,最终作为一个cube供用户查询。

原理


如上文所述,kylin使用了预计算的方法来加速查询,即针对一个星型拓扑结构的数据,预计算所有维度组合的指标,作为一个cube,保存在数据库中,提供特定模式sql的查询服务。首先给出kyin的架构:


kylin的整个架构包括三个部分:数据源(source),执行引擎(engine),存储(storage),元数据(metadata),其中执行引擎又分为查询引擎(sql查询转为cube查询)和cube构建引擎(构建cube)。以kylin2.1为例,其支持hive,kafka作为数据源,cube构建引擎支持spark和MapReduce,整体架构是一种可插拔的设计,支持自定义数据源,执行引擎和存储结构。此外,kyin支持查询push down操作,即对于cube不支持的sql,可通过上图中的Routing结构,将sql交由底层Hive执行。

概括的讲,kylin主要解决了以下两个问题:

  • cube预计算
  • sql查询转cube查询

cube预计算

kylin在计算cube时,有逐层算法和快速立方体算法,可根据用户需要进行配置。本文仅介绍逐层算法,因为其是最最容易理解的算法,并选择MapReduce作为执行引擎。核心部分是cuboid的计算,以示例中的3维模型为例,其可能的维度组合为:

图中每个顶点代表对应维数据的所有组合的指标结果集合,集合的元素个数等于各维度的基度值的乘积。以图中蓝色点为例,其代表不同手机在不同国家历年的总销量,假设phone的基度是4,国家的基度是8,那么该蓝色点包含有32(4*8)个cuboid。n维维度列的组合称为n-D cuboid,最高维cuboid也称为Base cuboid。cuboid的计算顺序由下至上,即先计算3个维度组合的cuboid,再计算2个维度组合的cuboid, 最后计算一个维度的cuboid:

  1. (2010, iphone, 中国)<time,phone,country>
  2. (2010, *,中国) <time,country>
  3. (2010,*,*) <time>

* 代表该列可取任意列值

除Base cuboid外,第n维cuboid结果可由n-1维结果聚合得到,以图中红色线为例,cuboid (2010,*,中国),可通过Base cuboid求和得到,即对2010年中国各手机品牌的销量求和。而Base cuboid可通过原始数据计算得到。

总的流程如下图所示:

  1. 根据star图,调用Hive,创建一张宽表
  2. 对宽表中的维度列去除,并存到hdfs中
  3. 为去重后的维度列建词典
  4. 读取宽表数据,计算base cuboid
  5. 基于base cuboid,计算次级 cuboid
  6. 将cuboid批量导入hbase中

每种维度组合,都有对应的cuboid id,使用了位编码的方式表示组合关系,2.1版本使用64位的long型表示,这里省略为8位。还是以示例为例,<time,phone,country>代表的base cuboid id是00000111, <time,country>代表的2-D cuboid id是00000101。在最后的Hbase中,RowKey是由cuboid id 和维度组合对应的词典编码后的值组合而成,每个度量对应一列。假设词典编码如下:

phone encode time encode country encode
苹果 0 2010 0 中国 0
华为 1 2011 1 美国 1
小米 2 2012 2 日本 2

以<time,phone>为例,其cuboid id为00000110,表示某一手机品牌在某年的总销量(totalSale
),最后cuboid的逻辑值为:

dimension metric
2011,苹果 200
2012,华为 300
RowKey totalSale
0000011010 200
0000011021 300

hbase对应的RowKey&Column值为

RowKey totalSale
0000011010 200
0000011021 300

自此,一个基本cube构建过程就结束了。理论上对于N维维度,存在2N次种维度组合,而对于每种维度组合,其包含的cuboid的个数与列的基度有直接关系。维度设置不合理,不仅会增加cube构建时间,也同时会导致膨胀率较大的cube,因此有必要去除不需要的维度和维度组合。

cube优化

kylin在cube预计算时,主要进行了两方面的优化:

  1. 提出了聚合组的概念,去除不必要的维度组合,加速cube构建。
  2. 宽表数据重新分配,避免数据倾斜。

首先看第一点——聚合组,这是一个将维度进行分组,以求达到降低维度组合数目的手段。不同的聚合组内的维度之间不会计算cuboid,cuboid个数会明显降低,假设原来有(m+k)个维度,现在分为两个维度为m和k的聚合组,那么维度组合从2(m+k)降为2m+2k。聚合组的优化措施与具体的查询sql联系紧密,是一种定制优化,如果查询sql包含的维度是跨聚合组的,那么kylin需要较大的代价进行N-Coboid的聚合,最终得到所需要的结果,这需要在cube构建时,做仔细的评估。

同时,在聚合组内又存在以下三种优化方式:

  • 强制维度(Mandatroy Dimensions)

    每次查询都会携带的维度

  • 层次维度(Hierarchy Dimensions)

    具有层次关系的维度组成一个Hierarchy,如年、月、日。在cube中,如果不设置Hierarchy,会有年、月、日、年月、年日、月日6个cuboid,但是设置了Hierarchy后,会增加一个cuboid约束,即低level的Dimension一定会伴随高Level的Dimension一起出现。因此会存在group by year, group by year,month的查询,但是不可以查询group by month,day。

  • 联合维度(Joint Dimensions)

    会一同出现的查询维度。cuboid要么都不包含这些维度,要么包含所有的维度。

对于第二点——数据重新分配,kylin会对宽表执行再分配策略,即调用Hive的Distribute by,若配置了shard by,则按照该列的值重新划分数据位置,否则随机分配。

sql查询转cube查询


kylin的sql查询基于calcite,其实现了自己的一套优化规则,可进行sql优化并获取sql中的table、aggreation等查询信息,具体映射规则如下:

  • table => cube
  • group, column => cuboid id
  • group,where => Row Key
  • aggreations => Row value

从sql中获取了hbase需要扫描的Row key和需要的指标值,最后只需要将cube值转为sql查询结果样式即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容