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