问题导读
1.为什么需要在Kylin创建Cube过程中使用Hive视图?
2.使用Hive视图,能够带来什么好处?
3.如何使用视图,使用视图有什么限制?
1. 为什么需要使用视图
Kylin创建Cube的过程中使用Hive的表数据作为输入源。但是有些情况下,Hive中的表定义和数据并不能满足分析的需求,例如有些列的值需要进行处理,有些列的类型不满足需求,甚至有时候我们在创建Hive表时为了方便快捷,会将Hive表的所有列的字段类型都定义为string,因此很多情况下在使用Kylin之前需要对Hive上的数据格式等问题进行适当的处理。
但是如果在Hive中通过修改原表来解决上面的问题,比如使用alter table的方式修改原始表的Schema信息未免会对其它依赖Hive的组件有所影响(例如可能导致通过Sqoop等方式导入数据失败),而且也有可能导致之前的作业无法正常运行。于是我们需要考虑在不改变原表的情况下解决这个问题,因此我们想到的方案是使用Hive的视图。
当然,除了Hive数据源本身Schema等限制之外,Kylin对于Hive的使用还有一定的限制,这也间接的导致我们需要使用视图:
A. 同一个项目下使用相同表(可能根据不同的filter条件过滤,或者设置了不同的维度等)创建了不同的Cube,会导致查询的时候定位到错误的Cube等异常问题。
B. 只支持星型模型
我们的来源表可能包含多张事实表和多张维表,那么就需要将多张事实表整合成一张大的宽表。
2. 如何使用视图
Hive目前只支持逻辑视图,而我们需要的仅仅是对Hive原始的Schema信息的修改,而并非希望通过物化视图优化查询速度,因此目前Hive对视图的支持可以满足Kylin的需要。
下面根据不同的场景分别介绍一下如何创建视图作为Kylin的输入源:
A. 分表的情况
两个表具有相同的结构,但是保存不同的数据,例如一个表保存Android端的访问数据,一个访问iOS端的数据,那么就可以通过Hive的view解决。
例如有一个用户有两张表product_android和product_ios,这两个表具有相同的表结构,用户需要将平台(Android或者IOS)作为一个维度进行分析,因此我们为其创建了这样的view:
[mw_shl_code=bash,true]create view palearn_cube as
select userid, eventid, label, day, 'android' as platformfrom palearn_android WHERE category='gc001'
UNION ALL
select userid, eventid, label, day, 'ios' as platform frompalearn_ios WHERE category='gc001'; [/mw_shl_code]
这样可以将palearn_cube作为事实表来创建Cube,其中而platform作为其中的一个维度
B. 自定义函数
Kylin中使用Apache Calcite作为SQL的查询引擎,但是Kylin支持的自定义函数代价比较大,因此如果需要使用自定义函数,那么可以在Hive中创建视图来对字段进行处理。
C. 雪花模型的支持
目前Kylin仅支持星型模型,而通过在Hive中创建视图,我们可以很容易地把雪花模型转换为星型模型,甚至生成一个大的宽表。
D. 频繁修改表字段名
Kylin直接使用Hive中的字段名作为元数据,如果频繁修改事实表或者维度表的字段名会导致元数据错误(https://issues.apache.org/jira/browse/KYLIN-1173),因此通过视图增加一层映射是比较好的方法,这样可以使得原生的Hive表的字段名对Kylin的Cube透明,此后再需要修改字段名的时候不会对Cube有所影响,只需要修改view的定义。
E. UHC维度
当一个维度的cardinality比较大时可能会出现的问题比较多,首先可能导致Extract Fact Table Distinct Columns这一步时导致reducer出现OOM;其次在创建维度字典树可能会导致维度字典树太大占据大量的内存;另外会导致cube的构建速度缓慢,占用大量的存储空间。此时就需要思考一下这样的UHC维度是否是必须的,是否可以提取出部分信息减小维度,例如timestamp维度,是否可以精确到5分钟,详细地址的维度,是否可以精确到县、镇,这样可以大大减小维度数,而且更详细的信息并没有太大的统计意义。例如url类型的维度,是否可以把参数去掉只保留访问路径。
F. Hive中表字段类型变化
比如我们之前有一个需求计算一个指标的Count Distinct值,虽然这个字段存放的内容为整数值,但是Hive表字段类型为string,Kylin中Count Distinct聚合函数不支持字符类型,因此我们在Hive中创建视图解决这个问题,即将string类型转换为整数类型。
G. 复合数据类型处理
由于Hive中可以定义复杂的数据类型,例如map、struct,而Kylin中无法处理这种类型,所以需要使用视图将复杂类型字段进行拆分出维度和度量。
在我们目前的实践中,有一部分Cube依赖的事实表都是通过view创建的,这样增加了一层映射,可以减小cube对原始表的依赖,提高灵活性。
3. 使用视图限制
由于Hive的限制,Hive不能对view使用HCatalog获取数据
(https://issues.apache.org/jira/browse/HIVE-10851),因此当你在Kylin中load一个view的时候,Kylin计算表的cardinality的job无法获取到cardinality的值,这时就要求用户知道每一列的cardinality大致的情况,如果实在不确定可以到Hive里面查询一下。
4. 使用视图实战
这里我给朋友们简单演示一下视图的使用,其实视图在我们项目中还是会经常遇到的。
不知道朋友们还记不记得之前我们创建过三张表(请查看“Apache Kylin进阶部分之多维分析的Cube创建实战”章节):
事实表:kylin_flat_db.web_access_fact_tbl
维表:kylin_flat_db. region_tbl
维表:kylin_flat_db.city_tbl
如果您根据本书实战的话,当前Hive的kylin_flat_db数据库下面应该有这三张表。我们现在将在Hive中对这三张表创建视图,根据视图来构建Cube,大概步骤如下:
步骤一:创建视图
在Hive Cli中执行如下SQL:
[mw_shl_code=bash,true]use kylin_flat_db;
create view v_pvuv as select a.DAYas v_date,
b.regionname,
c.cityname,
hash(a.cookieid) as cookieid,
a.pv
from web_access_fact_tbl a
join region_tbl b
on a.regionid = b.regionid
join city_tbl c
on a.cityid = c.cityid; [/mw_shl_code]
这里对cookieid字段(字符串类型)使用hash函数处理,结果处理为整数类型,我们这样做的目的是为了使用Count Distinct(目前只支持整数类型)精确去重。
注:hash算法的特点是可重复和不可逆的,即针对不同的字符串进行hash处理,结果可能会重复的,所以上面的方法存在一定的问题。在实际项目中我们使用Hive自定义函数对需要使用Count Distinct精确的字段(整数类型就不必处理了)处理成整数类型。
步骤二:创建项目
创建“view_project”工程,当然也可以使用任何已经存在的工程。
步骤三:导入数据源
导入kylin_flat_db数据库下刚才创建的视图v_pvuv。
步骤四:创建Model
这里我们作为演示,只选了一张视图作为事实表,没有维表。其中:
维度字段:v_date,regionname,cityname
度量字段:cookieid,pv
分区字段:v_date
步骤五:创建Cube
因为朋友们对于如何创建Cube都很熟悉了,这里我们简要罗列几步。
创建Cube所选的维度如下:
创建Cube所选的度量如下:
其中我们使用精确的COUNT_DISTINCT函数来计算cookieid字段中值,所以返回类型为bitmap。
步骤六:构建Cube
设置构建的结束时间,然后构建Cube。
步骤七:查询Cube
查询如下SQL:
[mw_shl_code=bash,true]select v_date,
regionname,
cityname,
count(distinct cookieid)
from V_PVUV
group by v_date,
regionname,
cityname; [/mw_shl_code]
结果为:
在我们使用Kylin的过程中,对于上面提到的问题很多都可以通过Hive的视图进行解决。如果朋友们在Kylin使用过程中遇到一些Kylin自身无法解决的时候,可以尝试一下Hive的视图,也许会给您带来惊喜。
|