Kylin + Mondrian + Saiku是一个简单的三层架构。git上开源的Saiku的项目已经整合了mondrian的jar包。所以构建这样一个三层架构主要的工作是将Mondrian的schema和Kylin的schema对应起来,同时需要针对Kylin的语法对Mondrian做一些Kylin dialect的定制开发。
Git上已经有一个整合Kylin,Mondrian以及Saiku的项目。照着这个项目的指引,可以很轻松的搭建这么一个三层的系统。在此,致谢开源项目作者mustangore。
本文主要介绍有赞数据团队为了满足在不同维度查看、分析重点指标的需求而搭建的OLAP分析工具。这个工具对Kylin、Mondrian以及Saiku做了一个整合,主要工作包括一些定制化的修改以及环境的配置。 目前这个系统还处于一个需要优化、完善的过程,这篇博文也会相应地更新。
在有赞发展的初期,数据团队主要的工作之一就是根据运营人员的报表需求,编写sql,从hive中获得数据并写入mysql中存储。最后,前端人员写相应的代码展现mysql中存储的报表数据。 随着公司业务的快速发展,如此长周期的报表开发流程已经很难跟上运营人员的分析需求了。为了避免深陷报表开发、维护的泥潭,数据组决定调研大数据场景下的OLAP分析工具。参考了明略数据的解决方案之后,我们选择整合Kylin,Mondrian,Saiku来实现这样一个OLAP系统。
三巨头
Kylin
kylin是apache软件基金会的顶级项目,一个开源的分布式多维分析工具。下面是摘自Kylin官网的介绍:
Apache Kylin™ is an open source Distributed Analytics Engine designed to provide SQL interface and multi-dimensional analysis (OLAP) on Hadoop supporting extremely large datasets, original contributed from eBay Inc.
个人的理解是:Kylin通过预计算所有合理的维度组合下各个指标的值并把计算结果存储到HBASE中的方式,大大提高分布式多维分析的查询效率。Kylin接收sql查询语句作为输入,以查询结果作为输出。通过预计算的方式,将在hive中可能需要几分钟的查询响应时间下降到毫秒级。更细致的关于Kylin的介绍,可以参考我的另一片博客Kylin初体验。
Mondrian
Mondrian is an Open Source Business Analytics engine that enables organizations of any size to give business users access to their data for interactive analysis. You can build powerful Business Intelligence solutions with Mondrian as your Online Analytical Processing (OLAP) engine, enabling multidimensional queries against your business data, using the powerful MDX query language.
Mondrian是一个OLAP分析的引擎,主要工作是根据事先配置好的schema,将输入的多维分析语句MDX(Multidimensional Expressions )翻译成目标数据库/数据引擎的执行语言(比如SQL)。
Saiku
Saiku allows business users to explore complex data sources, using a familiar drag and drop interface and easy to understand business terminology, all within a browser. Select the data you are interested in, look at it from different perspectives, drill into the detail. Once you have your answer, save your results, share them, export them to Excel or PDF, all straight from the browser.
Saiku提供了一个多维分析的用户操作界面,可以通过简单拖拉拽的方式迅速生成报表。Saiku的主要工作是根据事先配置好的schema,将用户的操作转化成MDX语句提供给Mondrian引擎执行。
架构图
Kylin + Mondrian + Saiku是一个简单的三层架构。git上开源的Saiku的项目已经整合了mondrian的jar包。所以构建这样一个三层架构主要的工作是将Mondrian的schema和Kylin的schema对应起来,同时需要针对Kylin的语法对Mondrian做一些Kylin dialect的定制开发。
Git上已经有一个整合Kylin,Mondrian以及Saiku的项目。照着这个项目的指引,可以很轻松的搭建这么一个三层的系统。在此,致谢开源项目作者mustangore。
一些细节
介绍完整体的结构,下面讲一些构建过程中遇到的坑。有些可能是我们的理解还不够深入,有些可能随着开源软件版本的升级已经不再是一个坑了。希望能给大家带来一些帮助,如果是由于我们理解的偏差导致踩到的坑,也希望大家留言给出指正:) 本套系统构建基于kylin1.5, Mondrian4.4以及Saiku3.7.4。底层是Hive0.14以及Hbase0.98。
前面提到,要让系统运转,Kylin的schema必须和mondrian的schema能够对接上。Kylin是根据自身cube配置的schema来进行预计算的,schema决定Kylin能够接收的sql查询的范围。Mondrian又根据自身的shema翻译MDX到sql, Mondrian的schema决定它生成的sql的范围。如果两者有不一致的情况,就可能导致Mondrian生成的sql无法被Kylin执行。 kylin的schema配置比较简单,管理页面上有一套图形界面指引你一步步地构建一个星型模型,配置di mension、measure。不过要把cube设计得高效,Kylin还是有不少高级地设置的,比如选择 attribute group, derived dimension等。官网上有详细的介绍。
Mondrian的schema没有比较好的图形配置工具,需要手写Mondrian schema的XML文档,文档格式参考官方文档,通过Saiku上传。
需要注意的坑:
不要用view作为lookup table 在设计Kylin cube时,用hive view作为fact table是一个比较好的实践方式,可以屏蔽一些底层数据结构变化对Kylin cube的影响。但是不要用view作look up table,在build cube计算维度表容量时会出问题。
Kylin无法在预计算指标时制定条件 比如有两个字段:orderpay, ispayed。我们可以配置sum(orderpay)作为订单金额, sum(ispayed)作为付款订单数。但是没法配置sum(orderpay) where ispayed = 1来表示付款订单金额。我们需要在fact view中添加字段payedorderpay表示付款的订单金额。
尽量在Kylin中用int类型 比如is_payed字段,就0/1两个值,通常我们在hive里可以设置为tiny int类型的字段。但是在Kylin中,针对tiny int 和 int类型的字段配置出来的measure类型是不一样的,tiny int 类型的字段得到的measure在和Saiku结合时可能会出现问题。
把hive表放在default库中 Kylin添加hive table的时候是可以指定hive table所在库的,但是建议将fact table、lookup table都放在default库中。因为在Mondrian的schema中,physical table是默认去default库查找的,目前还没有发现很好的在Mondrian schema中指定数据库的方式。
Kylin配置cube的时候可以指定某个measure的聚合方式为count distinct,有精准计算的方式也有基于hyperloglog算法的近似计算方式。同样,在Mondrian的schema里也可以配置count distinct的指标聚合方式。
看上去一切都OK,然而问题来了: Kylin的count distinct语法只针用count distinct聚合的指标字段,在计算维度表大小的时候,kylin无法计算类似 select count(distinct date) from lu_date这样的sql语句。在mustangore的项目中,对Mondrian打了Kylin-dialect的补丁。其中添加了一个JdbcDialect的实现:
public class KylinDialect extends JdbcDialectImpl {
public static final JdbcDialectFactory FACTORY =
new JdbcDialectFactory(KylinDialect.class, DatabaseProduct.KYLIN) {
protected boolean acceptsConnection(Connection connection) {
return super.acceptsConnection(connection);
}
};
/**
* Creates a KylinDialect.
*
* @param connection Connection
* @throws SQLException on error
*/
public KylinDialect(Connection connection) throws SQLException {
super(connection);
}
@Override
public boolean allowsCountDistinct() {
return false;
}
@Override
public boolean allowsJoinOn() {
return true;
}
}
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。