一.前言

前段时间,有个项目接触到kylin这门技术,后面公司要求每个人每个季度做一次演讲,于是就结合公司的业务讲kylin(ps:感觉公司这个制度挺好的,虽然是强制的,但是至少督促我们对以前用过的东西做一些总结以及挖深)。这篇blog就把上次讲解的ppt再吵一次饭吧

 

二.OLAP背景

企业随着数据量的越来越大,数据分析查询响应时间以及 及时性要求也越来越来越高,如果按照传统的ETL方式处理,对于灵活的维度组合查询的需求不是很适用,也比较麻烦。 而OLTP(on-line transaction processing) 是传统数据库的运用,主要用于日常的事务处理,例如银行交易。  在这种背景下,OLAP(on-line analytical processing) 分析引擎孕育而生

 

三.OLAP方案对比

Druid 设计到的组建较多,偏重,SQL支持相对较弱。但查询效率上较快(亿级别及以上数据量 待比较),实时查询效果好

ES 不支持跨天去重,SQL支持较弱,超大数据量的写入不稳定,但查询灵活

Kylin 支持SQL查询,WEB节点配置模型,随大数据增大查询效率影响较小,维度较多时,查询效率可能较低

 

四.kylin原理及核心概念

工作原理 :kylin先对数据模型做cube预计算,并将计算结果存储下来,即空间换时间的原理

核心概念: 维度和度量,维度通常记录一个属性,例如时间,地点,标签等。度量是居于数据所计算出来的统计值,例如 某商品销售总额,人群库中男性总人数

事实表和维度表:事实表主要记录原生数据,维度表主要用来保存维度的属性值

星形模型 :星形模型是一张事实表,以及零个或多个维度表。事实表和维度表通过主键和外键关联,维度表之间不关联

维度基数:维度基数表示该维度出现不同值的数量,比如国家是一个维度,那就有200多个不同的值

(ps: 这里只是列举了部分内容,详情见官方文档)

 

五.cubeid 转化为hbase key结构

  我们知道现阶段版本的kylin存储引擎是hbase,那在hbase中是如何存储的呢?大致过程描述如下,先上一张盗用图:

 

kylin学习笔记

字段编码:相信大家都明白,将一个长字符串转换为更短的字符串,这样减少存储在hbase数据量以及提高查询效率

00000001+0 :表示仅仅查询city=0,根据字典转换后 即是查询city=beijing,根据原始表可知1、2、4行符合记录加起来80(如果是00000011+xx 表示查询两个提交year 和city)

根据上面所描述的,hbase rowkey = cube id + 具体的维度值,要查询各个条件下的count值,最终只需要组装成相应的rowkey,直接 到hbase查询得到结果! kylin存储以及查询大致如上

 

六.kylin 构建cube 过程

过程如下图,后面会选择部分流程进行说明(ps:官网链接:http://kylin.apache.org/docs/howto/howto_optimize_build.html):

kylin学习笔记

1 . create intermediate hive table: 将需要的hive 事实表包括join的维度表所需的字段插入到临时中间表中,例如 insert table tmp_xxx   select x1,x2  from  fact_table left jon demension dimension_tablex1 on 条件   left join  ...

2. redistrubute intermediate table :故名思意,将上一步得到的临时中间表 进行shuffle 操作保证文件大小平衡 ( ps:  1)shuffle 规则 默认是随机random ;  2) 还可以指定某个维度值 即该维度相同的值会分配到同一个文件中,如何某个维度是高基数,按照该高基数分配,能提升后面cube计算的速度,当我们在计算后续base cubeid 的时候我们需要拿到该高基数的distinct 值,毕竟要在hbase构建所有的rowkey嘛,如果随机分配,那每个文件可能包含相同的值,不同文件需要去重其次每个文件去重后包含的值可能很大 eg.每个文件去重后包含所有不同的值;而按照高基数维度分配后不同的文件不存在相同的值,不同的文件间也就不需要去重--当然具体优化原理还需要看源码考证   3) 后面看到相关文件记录,如果有超高基数列的精确去重,可以按照列shuffle.kylin.source.hive.flat-table-cluster-by-dict-column=LOAD_UUID(精确去重指标的列名,不需要加Hive表名),该属性在kylin v2.2版本中没有,v2.3版本中有。优化原理是简化构建全局字典的过程。大致原理是,相同的值在同一个文件上,避免了重复加载字典(这里是指字典的一部分,该部分字典有 该值的映射关系,精确去重可以参考后面第八节内容)

3. extract fact table distinct columns 和bouild dimension dictionary: 如果字段类型使用字典编码,可以将字符串隐射为int值,能提高存储空间和查询效率。 其次字典是保存在内层中。 问题:如果基数很大,将占用很大的内层怎么办?

4. build base cuboid : base cuboid  表示计算所有维度参与的情况,比如有四个维度 A B C D ,那 base cubeid就是abcd  

5.  build N-Dimension cuboid: 居于上一层的cuboid 计算下一层的cuboid , 例如 abc的cuboid 可以从 abcd的cuboid 推出,相当于将d维度cut down 再聚合下。 问题: ab可以从abc  abd两个cubeid中推到,该如何选择?  

6. 后续步骤 主要将生成的文件 生成hfile 然后导入到 htable table  

 

七.cube 设计优化

 一个cube是所有维度的组合,如果有N个维度,就有2的N次方的组合,这个膨胀速度是相当大。但是有的时候我们并不需要查询所有组合的情况,因此在实际的开发中,对维度的优化是非常有必要的。

优化策列如下:

使用衍生维度 : 比如我们要查询select   user_name,user_id from xxx where  user_id=xxx。通用做法是增加user_id 和user_name 维度,但是user_id是可以推到出user_name,因此可以将user_name作为衍生维度,减少一个维度

强制维度:如果我们知道所有的查询肯定有某个维度,则可以将该维度设置为强制维度。这样将所有的cube数量减少到原来的1/2

层级维度:某些维度是有层级关系的,比如:有省 市两个 维度,查询条件有市的时候也一定有省

联合维度:每个联合包含两个维度或者更多的维度,这些维度要么一起出现要么都不出现

创建多个聚合组:比如 a b c 三个维度,b 和c不会同时出现,则可以设置a b 为一个聚合组,a c为另一个聚合组

 

八.kylin精确去重

在公司现有的业务中,主要的业务就是distinct count ,所以将精确去重单独地说一下。 新版本(V2.3)kylin采用bitmap来精确统计,我们知道bit 存储的0或者1,eg.假设我们需要统计总人数,可以用bit[] 来表示所有人是否存在的分布情况,bit数组的索引值表示用户id,对应的值表示是否存在(1表示存在,0表示不存在)即如果bit[15]=1表示用户id=15的用户存在。 使用bitmap最大的优点是:用bit存储节省了很大的空间开销,其次执行 sql中的and 或者 or 等操作直接等价于bit[]对应的 &  | 等操作 。 所以后面公司重构该项目,直接用基于bitmap实现的方案

看到这我们会发现,我们需要数值类型,如果我们精确统计列 本来是int类型可以直接用,但是如果是非数值类型(eg.string)我们就需要将string 类型映射为int值 ,该过程俗称构建全局字典。( 更详细大家可以参看blog:https://blog.bcmeng.com/post/kylin-distinct-count-global-dict.html

 

九. kylin痛点及展望

 根据前面内容可知,kylin会将cubuid+各个维度具体的值拼接成hbase的rowkey, 但hbase 是单一rowkey索引,根据rowkey的前缀查询固然高效,但总免不了一些维度排在后面。为此除了为hbase创建索引外,还可能的途径是不用hbase存储cube 的计算结果比如lucence等

 

 

相关文章: