mondrian是一个开放源码的Rolap服务器,使用java技术开发。它实现了xmla和jolap规范。并且支持由Microsoft,Hypeion等公司研究的多维查询表达式MDX(类似于sql)。
到目前关于Mondrian的资料还是相对较少。多数就是对官网上的demo基础的使用并没有具体在项目中的具体集成和使用。
Mondrian下载:https://sourceforge.net/projects/mondrian/
Mondrian API:https://mondrian.pentaho.com/documentation/architecture.php
先来一张官方的图:
整个Mondrian分为四层:
1.表现层(presentation layer):
从最上面可以看到mondrian的入口
1).HTTP(JPivot)得到结果,并且官方提供的war包就是就是基于此的,但是通过资料的查新这个现实层以及停止维护已经很老并且并不是基于mvc模式开发,舍弃掉。
2).XML/HTTP也是官方提供的,舍弃。
3).JAVA通过API调用得到结果,这个正是我想要的,通过集成到java web中展示层则使用echarts等工具。
2. 计算层(dimmensinal layer):分析和校验MDX语句,并且将分析后的语句发送到聚集层进行聚集
3.聚集层(star layer):聚集层是一个缓冲层对一些操作过的数据进行缓存提供系统的性能。
4.存储层:提供聚集的元数据,可以在多台机器上。
通过上面可以了解到我们接触到比较多的是展示层和存储层和计算层的MDX语句的编写。
先通过Java做一个demo 吧。
先准备环境:搭建存储层
表结构:
需要的jar包
需要用到的聚集文件:
<Schema name="db">
<!--创建一个数据立方体-->
<Cube name="Sales" visible="true" cache="true" enabled="true">
<!--事实表 使用name指定表名-->
<Table name="sale">
</Table>
<!--维度1 foreignKey 事实表中的外键id name维度名称 -->
<Dimension visible="true" foreignKey="cusId" highCardinality="false" name="cusGender">
<!--维度细分的层次 allMemberName 所有维度的名称 primaryKey维度表的主键 hasAll是否包含所有维度-->
<Hierarchy visible="true" hasAll="true" allMemberName="allGender" primaryKey="cusId">
<!---->
<Table name="customer">
</Table>
<!--定义层次的水平,column 维度表的那一列 .... -->
<Level name="gender" visible="true" column="gender" type="String" uniqueMembers="false" levelType="Regular" hideMemberIf="Never">
</Level>
</Hierarchy>
</Dimension>
<Dimension visible="true" foreignKey="proId" highCardinality="false" name="proType">
<!--primaryKey 维度主键 primaryKeyTable维度主键对应的表-->
<Hierarchy visible="true" hasAll="true" allMemberName="allPro" primaryKey="proId" primaryKeyTable="product">
<!--两张表外键关系-->
<Join leftKey="proTypeId" rightKey="proTypeId">
<Table name="product">
</Table>
<Table name="producttype">
</Table>
</Join>
<!--具体的维度 -->
<Level name="proTypeId" visible="true" table="producttype" column="protypeid" nameColumn="protypename" type="String" uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
</Level>
<Level name="proId" visible="true" table="product" column="proId" nameColumn="proName" type="String" uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
</Level>
</Hierarchy>
</Dimension>
<!--事实表 aggregator 统计时使用的函数 sum累加 formatString 格式化字符串,可以格式化类似Money、时间之类的格式-->
<Measure name="numb" column="number" datatype="Numeric" aggregator="sum"></Measure>
<Measure name="totalSale" formatString="¥#,##0.00" aggregator="sum">
<!--sql 片段-->
<MeasureExpression>
<SQL dialect="generic">
<![CDATA[(unitPrice*number)]]>
</SQL>
</MeasureExpression>
</Measure>
<CalculatedMember name="averPri" dimension="Measures">
<Formula>
<![CDATA[[Measures].[totalSale] / [Measures].[numb]]]>
</Formula>
<CalculatedMemberProperty name="FORMAT_STRING" value="¥#,##0.00">
</CalculatedMemberProperty>
</CalculatedMember>
</Cube>
</Schema>
Java demo文件 为了方便就直接写的main
package com.yanghs.test;
import mondrian.olap.Result;
import org.apache.log4j.PropertyConfigurator;
import org.olap4j.*;
import org.olap4j.metadata.Member;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author yanghs
* @Description:
* @date 2018/4/21 11:49
*/
public class demo1 {
public static void main(String[] args) throws FileNotFoundException {
OlapConnection conn = null;
try {
InputStream is = new BufferedInputStream(new FileInputStream("G:\\mycode\\mondriandemo\\src\\main\\javacode\\com\\yanghs\\test\\log4j.properties"));
PropertyConfigurator.configure( is);
conn= getConnection(
//URL协议
"jdbc:mondrian:"
//连接数据源的JDBC连接
+ "Jdbc='jdbc:mysql://localhost:3306/testdb?user=root&password=123456&useUnicode=true&characterEncoding=utf8';"
//数据模型文件
+ "Catalog=G:\\mycode\\mondriandemo\\src\\main\\javacode\\com\\yanghs\\test\\qiuschema.xml;"
//连接数据源用到的驱动
+ "JdbcDrivers=com.mysql.jdbc.Driver;");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//查询语句
String mdx="SELECT {[Measures].[numb]} ON 0,{[proType].[proId].members} on 1 FROM [Sales]";
CellSet cs= null;
try {
cs = getResultSet(mdx, conn);
} catch (OlapException e) {
e.printStackTrace();
}
/*遍历结果*/
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();
}
}
}
/**
* 得到连接
* @param 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);
return connection.unwrap(OlapConnection.class);
}
/**
* 得打查询的结果
* @param mdx
* @param conn
* @return
* @throws OlapException
*/
public static CellSet getResultSet(String mdx, OlapConnection conn) throws OlapException {
OlapStatement statement = conn.createStatement();
CellSet cellSet = statement.executeOlapQuery(mdx);
return cellSet;
}
}
运行结果
rows:[proType].[shiwu].[baozi]
columns:[Measures].[numb]
values:3.0
rows:[proType].[shiwu].[mantou]
columns:[Measures].[numb]
values:3.0
rows:[proType].[diannao].[hp]
columns:[Measures].[numb]
values:58.0
rows:[proType].[diannao].[lenovo]
columns:[Measures].[numb]
values:77.0
rows:[proType].[diannao].[asus]
columns:[Measures].[numb]
values:54.0
rows:[proType].[jiaju].[zhuozi]
columns:[Measures].[numb]
values:36.0
rows:[proType].[jiaju].[yizi]
columns:[Measures].[numb]
values:57.0
通过日志文件打印了查询sql语句,olap引擎把mdx语句翻译为sql查询数据。
通过上面mdx语句执行是不是很像jdbc的编程,其实mondrian做的事情就是把mdx语句翻译为sql语句,而mdx语句是专门用来做多维数据分析。
这个项目很小就不上传了,建表语句和pom.xml 及我的maven下载不到的jar包。
下载:https://pan.baidu.com/s/1OiYEE1aaWYEiJhZr6elhqw