mondrian是一个OLAP引擎,和OLTP不同的是,OLAP是建立在物理表以上的一个逻辑模型,称为一个立方体,这个立方体的建立是通过指定可选的维度和度量,每一个维度有一个维度表,维度有层次信息。OLAP的查找是通过一种MDX表中实现的,类似于OLTP的sql语法,MDX有自己的语法,不过它只规范了查询语句,因为OLAP中不会对数据进行修改,因此OLAP执行的过程中有两个方面,首先就是对模型的定义,在mondrian中,逻辑模型的定义是通过xml的方式交给mondrian解析的,对于这个模型的查询是通过MDX格式的语句完成的,下面通过一个实例调用mondrian接口看一下mondrian的使用。
package mondrianTest;import java.io.PrintWriter;import mondrian.olap.Connection;
import mondrian.olap.DriverManager;
import mondrian.olap.Query;
import mondrian.olap.Result;public class TestMDX {
public void testQuery(){Connection connection = DriverManager.getConnection("Provider=mondrian;" + "Jdbc=jdbc:mysql://10.241.20.157:3306/foodmart?user=root&password=root;" +"Catalog=C:\\Users\\Administrator\\Desktop\\nrtp\\FoodMart.xml;",null, false);Query query = connection.parseQuery("select {[Measures].[业务量]} on columns from MsgBusi");Result result = connection.execute(query);PrintWriter pw = new PrintWriter(System.out);result.print(pw);pw.flush();}public static void main(String[] args) {TestMDX a =  new TestMDX();System.out.println("调用mondrian api进行查询");a.testQuery();}
}
这段代码是自己从网上down下来的,要想运行它需要加一些执行过程中需要的jar包,至少需要以下几个包:

接着运行出现如下错误:
Exception in thread "main" mondrian.olap.MondrianException: Mondrian Error:Internal error: while parsing catalog C:\Users\Administrator\Desktop\nrtp\FoodMart.xml
at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:755)
at mondrian.olap.Util.newInternal(Util.java:1083)
at mondrian.olap.Util.newError(Util.java:1099)
at mondrian.rolap.RolapSchema.load(RolapSchema.java:303)
at mondrian.rolap.RolapSchema.<init>(RolapSchema.java:213)
at mondrian.rolap.RolapSchema.<init>(RolapSchema.java:76)
at mondrian.rolap.RolapSchema$Pool.get(RolapSchema.java:835)
at mondrian.rolap.RolapSchema$Pool.get(RolapSchema.java:657)
at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:148)
at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:79)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:122)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:87)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:55)
at mondrianTest.TestMDX.testQuery(TestMDX.java:13)
at mondrianTest.TestMDX.main(TestMDX.java:41)
Caused by: org.eigenbase.xom.XOMException: In Schema: In Cube: In Measure: In MeasureExpression: In SQL: Value 'infobright' of attribute 'dialect' has illegal value 'infobright'.  Legal values: {generic, access, db2, derby, firebird, hsqldb, mssql, mysql, oracle, postgres, sybase, teradata, ingres, luciddb}
at mondrian.olap.MondrianDef$Schema.<init>(MondrianDef.java:134)
at mondrian.rolap.RolapSchema.load(RolapSchema.java:289)
... 11 more
这一步是解析模式定义的xml文件出现了错误,根据提示,查看了一下infobright是什么发现它也是一种数据仓库的解决方案,可能当前版本的mondrian不支持它,所以将出现他的xml标签都注释掉算了,反正我们这里只使用mysql(要确保mysql的连接驱动的jar包已经加入到工程的classpath下),不关心其他的。
接着再次运行出现如下错误:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failureThe last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1137)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:355)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2490)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2527)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2309)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:834)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:46)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:408)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:419)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:344)
at java.sql.DriverManager.getConnection(Unknown Source)
at java.sql.DriverManager.getConnection(Unknown Source)
at mondrianTest.TestMysql.main(TestMysql.java:17)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:258)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:305)
... 15 more
这个错误从堆栈上看是connect引起的,通过http://stackoverflow.com/questions/2983248/com-mysql-jdbc-exceptions-jdbc4-communicationsexception-communications-link-fai的解析发现时由于没连上服务器导致的,但是明明服务器的3306端口已经打开了啊,而且在服务器上使用mysql客户端就可以连接上去啊。这是怎么回事,使用tcpdump抓包发现每一次SYN请求都会被服务器无情的回复RST报文,这说明该端口确实没有打开,使用netstat查看该端口发现的确:

原来服务器只接收本地的连接,怪不得我在windows上一直连不上呢,解决的方法就是修改mysql的配置文件my.conf,把其中的bind-address从原来的127.0.0.1修改为0.0.0.0,这样就可以从远程连接到mysql了。
接着重新运行又出现这样的错误:

Exception in thread "main" mondrian.olap.MondrianException: Mondrian Error:Failed to parse query 'select {[Measures].[业务量]} on columns from MsgBusi'
at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:755)
at mondrian.olap.ConnectionBase.parseQuery(ConnectionBase.java:77)
at mondrian.olap.ConnectionBase.parseQuery(ConnectionBase.java:59)
at mondrianTest.TestMDX.testQuery(TestMDX.java:18)
at mondrianTest.TestMDX.main(TestMDX.java:37)
Caused by: mondrian.olap.MondrianException: Mondrian Error:Error while parsing MDX statement 'select {[Measures].[业务量]} on columns from MsgBusi'
at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:755)
at mondrian.olap.Parser.parseInternal(Parser.java:760)
at mondrian.olap.ConnectionBase.parseQuery(ConnectionBase.java:74)
... 3 more
Caused by: mondrian.olap.MondrianException: Mondrian Error:MDX cube 'MsgBusi' not found or not processed
at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:752)
at mondrian.rolap.RolapSchema.lookupCube(RolapSchema.java:1067)
at mondrian.olap.Query.<init>(Query.java:187)
at mondrian.olap.Parser.makeQuery(Parser.java:851)
at mondrian.olap.CUP$Parser$actions.CUP$Parser$do_action(Parser.java:1700)
at mondrian.olap.Parser.do_action(Parser.java:685)
at java_cup.runtime.lr_parser.parse(lr_parser.java:569)
at mondrian.olap.Parser.parseInternal(Parser.java:755)
... 4 more
这个是查询MDX中出现的错误了,这说明前面的连接mysql,解析xml文件的操作都执行成功了,根据错误提示发现MsgBusi不存在,查看xml文件发现这个MsgBusi的确不存在,这才想起来,原来down下来的代码和我用的逻辑模型的定义不是同一个,我这里用的是mondrian提供的一个示例foodmart,所以我应该用我这里的逻辑模型定义的立方体和维度等进行查询。所以需要修改一下MDX语句,经过多次测试之后发现这样的语句能够在当前的配置中跑出结果:SELECT  { [Measures].[Unit Sales] } on columns,{ [Time].[Year].[1997] } on rows FROM Sales  WHERE ([Customers].[State Province].[CA]),跑出的结果如下:
Axis #0:
{[Customers].[USA].[CA]}
Axis #1:
{[Measures].[Unit Sales]}
Axis #2:
{[Time].[1997]}
Row #0: 74,748
但是我发现mondrian的版本很多,当前最新的版本已经是4.0版本的了,而能够刚才使用的版本还是2.x版本的,然后发现在较新的版本中都在使用olap4j这样的接口进行访问,这个接口类似于jdbc访问数据库引擎,是一个java的接口规范,用于访问ROLAP引擎,使用mdx语句,于是就换成当前最新的稳定版本3.9进行测试,换了之后发现出错了:
Exception in thread "main" java.lang.NoSuchMethodError: mondrian.resource.MondrianResource.getThreadOrDefaultLocale()Ljava/util/Locale;
at mondrian.resource.MondrianResource.instance(MondrianResource.java:29)
at mondrian.rolap.aggmatcher.AggTableManager.<clinit>(AggTableManager.java:54)
at mondrian.rolap.RolapSchema.<init>(RolapSchema.java:194)
at mondrian.rolap.RolapSchema.<init>(RolapSchema.java:216)
at mondrian.rolap.RolapSchemaPool.get(RolapSchemaPool.java:214)
at mondrian.rolap.RolapSchemaPool.get(RolapSchemaPool.java:66)
at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:160)
at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:90)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:112)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:68)
at mondrian.olap.DriverManager.getConnection(DriverManager.java:50)
at mondrianTest.TestMDX.testQuery(TestMDX.java:13)
at mondrianTest.TestMDX.main(TestMDX.java:38)
妈的,找不到这个函数,真是奇怪了,这个包也存在,包里面也有这个类,为什么偏偏就没有这个函数呢?!这就是java比较烦人的地方,在C/C++里面编译期间必须能够找到所有的函数定义,虽然有些函数的实现没有找到,在装载的时候也会首先进行动态链接,而不会在执行的时候再进行,但是JAVA这种只有在使用的时候再进行load的方式就很可能出现这种动态的错误,例如找不到class、找不到method等等,这个问题查了半天也没有能够找出错误,最后是在没有办法了采取最后的方法:查看源码。幸亏有grepCode这样的网站,真的是让查看java源代码方便了不知道多少个数量级,俗话说:源码在手,了无秘密。有了源码,什么问题都不在是问题了,在grepcode中查找mondrian.resource.MondrianResource这个类,发现在mondrian中只有3.6.7之前的版本才有,所以又不得不切换回3.6.x版本,这里我用的是3.6.1版本,换了jar包之后发现这个错误还是存在,好吧,看下代码吧。
在代码中,的确是MondrianResource的instance方法中(29)行调用了getThreadOrDefaultLocale函数,而在当前的类中没有定义这个函数,那么它一定是继承另外一个类,在父类中实现的,果然,它继承的是org.eigenbase.resgen.ShadowResourceBundle类,再查看一下这个类,我擦,在codegrep上根本搜不到这个类的源码,这时候请教google吧,搜出来这个网页:http://www.java2s.com/Code/Jar/e/Downloadeigenbaseresgenjar.htm,我勒个咔擦,我之前下载的eigenbase-resgen.jar文件不就是在这里下载的吗?!而这个jar包中分明有org.eigenbase.resgen.ShadowResourceBundle类啊(要不然我的代码编译都不会通过的),一切又绕回来了,这时候该怎么办?
这时候我想起来了,既然mondrian自己能够编译通过,顺利执行,那么无论是在mondrian的maven依赖包中,还是在saifu中都应该有这个包的依赖,而且这个包应该就是可以使用的,而之前的eigenbase-resgen.jar不能使用可能是因为版本问题,查看了mondrian的pom.xml文件,发现它使用的是如下的版本:

<dependency><groupId>eigenbase</groupId><artifactId>eigenbase-resgen</artifactId><version>1.3.1</version></dependency>

查看了saiku的pom.xml文件,它使用的是如下的版本:

<dependency><groupId>eigenbase</groupId><artifactId>eigenbase-resgen</artifactId><version>1.3.0.11873</version>
</dependency> 
虽然这两个版本不一样,但是我想应该任何一个都可以吧,于是下了1.3.1版本的,将之前的jar包换了一下之后测试一下,OK了,得到了同样的结果。
虽然得到了相同的结果,但是这里还是使用mondrian之前的execute接口来执行MDX语句的,而不是通过olap4j的方式,代码中可以看到execute接口已经被抛弃了,查看mondrian文档看到这样的注释:
Deprecated. This method is deprecated and will be removed in mondrian-4.0. It operates by internally creating a statement. Better to use olap4j and explicitly create a statement.
这里说这个接口将在mondrian 4.0以后被移除了,建议使用olap4j接口创建statement的方式代替,于是又在网上搜到一片mondrian教程(http://alenzhai.iteye.com/blog/2158953),这里使用的就是olap4j的方式访问的,把代码copy下来之后进行修改,保持connection的参数和mdx语句不变,运行过之后能够得到相同的结果,只不过这种访问方式更加规范。附上源代码:

package mondrianTest;import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.olap4j.Cell;
import org.olap4j.CellSet;
import org.olap4j.OlapConnection;
import org.olap4j.OlapException;
import org.olap4j.OlapStatement;
import org.olap4j.OlapWrapper;
import org.olap4j.Position;
import org.olap4j.metadata.Member;public class Olap4jTest {     /*** 获取连接Olap的连接* @param url  连接Olap的URL* @return* @throws ClassNotFoundException* @throws SQLException*/public static OlapConnection getConnection(String url) throws ClassNotFoundException, SQLException{Class.forName("mondrian.olap4j.MondrianOlap4jDriver");Connection connection = DriverManager.getConnection(url);OlapConnection olapConnection = connection.unwrap(OlapConnection.class);return olapConnection;}/*** 获取查询的结构结果集* @param mdx  mdx查询语句* @param conn Olap连接* @return* @throws OlapException*/public static CellSet getResultSet(String mdx,OlapConnection conn) throws OlapException{OlapStatement statement = conn.createStatement();CellSet cellSet = statement.executeOlapQuery(mdx);return cellSet;}public void testQuery(){               OlapConnection connection = null;try {connection = getConnection("jdbc:mondrian:" + "Jdbc=jdbc:mysql://10.241.20.157:3306/foodmart?user=root&password=root;" +"Catalog=C:\\Users\\Administrator\\Desktop\\nrtp\\FoodMart.xml;");} catch (ClassNotFoundException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}String query = "SELECT  { [Measures].[Unit Sales] } on columns,{ [Time].[Year].[1997] } on rows FROM Sales  WHERE ([Customers].[State Province].[CA])";//获取查询结果  CellSet cs = null;try {cs = getResultSet(query, connection);} catch (OlapException e) {// TODO Auto-generated catch blocke.printStackTrace();} PrintWriter pw = new PrintWriter(System.out);//处理返回数据if(cs.getAxes().size()>1){for (Position row : cs.getAxes().get(1)) {for (Position column : cs.getAxes().get(0)) {for (Member member : row.getMembers()) {System.out.println("rows:"+member.getUniqueName());}for (Member member : column.getMembers()) {System.out.println("columns:"+member.getUniqueName());}final Cell cell = cs.getCell(column, row);System.out.println("values:"+cell.getValue());System.out.println();}}}else{for(Position column:cs.getAxes().get(0)){for(Member member:column.getMembers()){System.out.println("columns:"+member.getUniqueName());}Cell cell=cs.getCell(column);System.out.print("values:"+cell.getValue());System.out.println();}}}public static void main(String[] args) {Olap4jTest a =  new Olap4jTest();System.out.println("调用mondrian api进行查询");a.testQuery();}
}
执行的输出结果如下:
rows:[Time].[1997]
columns:[Measures].[Unit Sales]
values:74748.0
最后看一下使用的jar包的信息:

ok,测试完成了。虽然过程很曲折,但是也学到了一些新知识,这里只是对mondrian做了一个简单的demo,证明了通过api调用的方式使用olap4j可以使用后端的mysql进行olap操作,接下来还需要了解mondrian对于hive和sql on hbase的支持,今天又发现一个新的开源OLAP引擎:Kylin,这个是eBay开源的,它是一个MOLAP引擎,和mondrian(ROLAP引擎)不同的是它会在创建Cube的时候将需要展示的维度和度量聚合到一个表中,并且将这个表进行物化,保存在HBASE中,之后的查询操作不是通过MDX标准来完成的,而是对物化表的SQL查询,这样的优点就是查询速度非常快,但是物化的过程需要一定的时间,并且物化表并不一定能够完全支持所有的cude操作,如果不能支持的话还是通过ROLAP的方式到hive表中动态查找(类似于mondrian),而mondrian不需要保存任何数据(除了mondrian的元数据),所有的MDX查询操作都是动态的生成sql,交由后端的数据库执行完成的,这些sql很可能是多表的join操作,对于hive而言可能性能上是一个很大的问题。
我觉得mondrian的学习主要在于两个方面:cude的定义和MDX查看,所以接下来还需要学习一个mondrian中生成cube的xml文件的格式,如何定义一个cube、MDX的语法等,先做一个后端连接hive的demo吧。

mondrian使用测试相关推荐

  1. Mondrian 4 测试的简单demo(Saiku简单测试Schema文件)

    ## 整理此文章方便大家做测试(手写Mondrian Schema自测),不必每次都向saiku上传文件了 ## 关键文件 * foodmart4.xml  测试对应的schema文件 * foodm ...

  2. Kylin, Mondrian, Saiku系统的整合

    本文主要介绍有赞数据团队为了满足在不同维度查看.分析重点指标的需求而搭建的OLAP分析工具.这个工具对Kylin.Mondrian以及Saiku做了一个整合,主要工作包括一些定制化的修改以及环境的配置 ...

  3. Mondrian 4: Get ready!

    蒙德里安4:做好准备! Mondrian是一种非常流行的开源分析引擎,可用于各种产品(如Pentaho BA Server,JasperSoft BI Server).Mondrian 4带来了一大堆 ...

  4. Mondrian简介

    出自:https://www.cnblogs.com/lk-fxtx/p/7067720.html 一.  Mondrian简介 Mondrian是一个开源项目.一个用Java写成的OLAP引擎.它用 ...

  5. mondrian的个人总结

    1. OLAP的作用和功能 OLAP(On-Line Analysis Processing)在线分析处理是一种共享多维信息的快速分析技术:OLAP利用多维数据库技术使用户从不同角度观察数据,它用于支 ...

  6. mondrian mysql 实例_mondrian入门 | 学步园

    以前一直是用MS Anylize Service的,最近要做的项目是java的,小项目预算有限,所以想找一个开源的java的数据仓库解决方案来用用. 在网上查了一下,发现了Mondrian.Mondr ...

  7. mondrian 性能优化

    mondrian作为开源的rolap引擎非常稳定,bug也非常少,但是就是基本没用人维护了,如果出现什么问题,需要自己修改源码了.现在很多BI工具的rolap引擎都使用的是modnrian ,例如比较 ...

  8. 配置Mondrian源码

    一,配置 前一阶段对mondrian和jpivot的测试主要建立在jar与war包的基础上面,若要对mondrian源码进行跟踪调试,需要导入mondrian源码包到ide(eclipse)环境中,在 ...

  9. locust入门:单机使用locust运行压力测试

    locust的官方文档在这里: http://docs.locust.io/en/stable/ 前置:locust的测试脚本使用为python(若未安装python环境,可以搜索安装python) ...

最新文章

  1. getpass 模块
  2. SD--关于定价过程中的存储顺序的参考结构和参考字段的使用代码跟踪
  3. oracle 触发器 upsert,如何使SQLAlchemy insert与Postgres多处理proof upsert触发器一起工作?...
  4. ERROR org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode: Exception in doCheckpoint
  5. 未雨绸缪 | 一文简介 Azure Front Door
  6. 基于Echarts+HTML5可视化数据大屏展示—Echart图例使用
  7. k8s核心技术-集群安全机制(概述)---K8S_Google工作笔记0038
  8. codekit for mac(开发人员必备编译工具)
  9. NAND闪存(NAND Flash)颗粒SLC,MLC,TLC,QLC的对比
  10. ccProxy软件实现网络共享
  11. Android编译内核并刷入
  12. CTWAP下程序崩溃
  13. MYCNCART博客系统
  14. 管理计算机域的内置账户怎么取消,如何删除供来宾访问计算机或访问域的内置账?...
  15. 网络学习 2g 3g 4g 技术对比 带宽理解 三大运营商手机网络模式 (制式)
  16. ACM第一次练习—1000A
  17. python键盘记录器_使用Python设计键盘记录器
  18. JPA 7. Spring 整合 JPA
  19. 金融申请评分卡(2)
  20. php中push数组,php中的array_push函数怎么用

热门文章

  1. html语言link,HTML中link是什么意思?
  2. 2022多益网络春招之最后一场--软件工程师笔试
  3. mysql 增加合计行_SQL:给查询添加一个合计行
  4. 用do…while循环按公式e=计算 e 的值(精度为 1e-6)
  5. 简单网站统计功能的实现 PV IP 真实访客数(UV)
  6. CANopen中SDO、PDO、以及COB-ID理解
  7. 网络广告VS电子邮件
  8. Ubuntu18.04——正确安装英伟达(NVIDIA)显卡驱动的一种简便方法
  9. bytestobstr php,一段asp转php
  10. 17、Health Check 健康检查