一、引言
Mondrian,
蒙得里安?皮特
1872-1944
荷蘭畫家,作品以交錯的三原色為基色的垂直線條和平面為特點,他的著作包括
新造型主義
(1920
年),對抽象藝術(shù)的發(fā)展曾經(jīng)產(chǎn)生很深影響。金山詞霸如是說。
不過
,
本文所要討論的可不是這位藝術(shù)家。那到底
mondrian
是什么呢?
Mondrian
是一個開源項目。一個用Java寫成的OLAP(在線分析性處理)引擎。它用MDX語言實現(xiàn)查詢,從關(guān)系數(shù)據(jù)庫(RDBMS)中讀取數(shù)據(jù)。然后經(jīng)過Java API用多維的方式對結(jié)果進(jìn)行展示。
我們都知道,在線分析處理(OLAP)要實時地分析大量數(shù)據(jù)。“online”這個詞的含義就是即使相關(guān)的數(shù)據(jù)量是巨大的可能以GB為單位系統(tǒng)也要足夠快的響應(yīng)以顯示結(jié)果。
OLAP
用了多維分析的技術(shù)。盡管關(guān)系型數(shù)據(jù)庫所存儲的所有數(shù)據(jù)都是以行和列的形式存在的,但一個多維數(shù)據(jù)集還是可以由軸(axes)和單元(cell)組成。
?
在上面的例子中,時間是個維度(
dimension
),而它下面的層次(
Hierarchies
)又分為半年、季度等級別(Level)。
二、感性認(rèn)識,運(yùn)行一個小實例
我們暫時先不討論Mondrian所用到的一些技術(shù)。我們可以先從一個小例子開始,不必在意每個細(xì)節(jié),只是希望大家有個感性認(rèn)識先。在實施這個例子的過程中,或許讀者就能見些端倪。
首先應(yīng)該到http://sourceforge.net/projects/mondrian/下載mondrian的最新版本。這是一個zip包,包括我們要用到的lib和一個例子。
當(dāng)然,讀者完全可以運(yùn)行mondrian自帶的實例,不過這個例子有些紛繁復(fù)雜,除了Mondrian本身還有其它技術(shù)在里面,不大容易講清楚,也不太適合初學(xué)者學(xué)習(xí)。所以,筆者在這里設(shè)計一個簡潔干凈的最小化實例。
本文所闡述的實例環(huán)境是Windows2000+Tomcat+Oracle。并且認(rèn)為讀者已經(jīng)針對jdk和Tomcat做了正確的開發(fā)環(huán)境的設(shè)置。
2
.
1
準(zhǔn)備工作
在%Tomcat%/webapp依次建立mywebapp,mywebapp/WEB-INF,mywebapp/WEB-INF/lib,把
mondrian.jar,javacup.jar,
x
alan.jar,junit.jar
等相關(guān)的jar包copy到
%
TOMCAT_HOME%/
webapps/mywebapp/lib
下。
2
.
2
數(shù)據(jù)庫結(jié)構(gòu)
在這個tiny的系統(tǒng)中,數(shù)據(jù)庫有3個表tb_employee(職員表),tb_time(時間表),tb_salary(薪酬表)。表結(jié)構(gòu)如下:
drop table tb_employee;
create table tb_employee
(
???? employee_id???? number,???????????? --
職員id????
???? employee_name?? varchar2(10)??????? --
職員姓名
);
?
drop table tb_time;
create table tb_time
(
??? time_id?? number,??????? --
時間id
??? the_year? char(4),?????? --
年
??? the_month char(2)??????? --
月
);
?
drop table tb_salary;
create? table tb_salary
(
??? employee_id? number,??????????????? --
職員id???
??? time_id????? number,??????????????? --
時間id
??? salary?????? number(19,4)?????????? --
薪酬
);
?
當(dāng)然,為了使系統(tǒng)能夠運(yùn)行,還需要讀者向數(shù)據(jù)庫表中插入一些數(shù)據(jù)。
2
.
3
根據(jù)數(shù)據(jù)庫表的結(jié)構(gòu),書寫
schema
文件
<?xml version="1.0"?>
<Schema name="Mondrian">
<Cube name="CubeTest">
??? <Table name="TB_SALARY" />
???
??? <Dimension name="Employee"? foreignKey="EMPLOYEE_ID" >
??????? <Hierarchy hasAll="true" primaryKey="EMPLOYEE_ID">? ???????
??????????? <Table name="TB_EMPLOYEE" />
??????? <Level name="employeeId" column="EMPLOYEE_ID"?? uniqueMembers="true" >
??????????????? <Property name="employeeName" column="EMPLOYEE_NAME"/>
??????????? </Level>
??????? </Hierarchy>
??? </Dimension>
??? <Dimension name="Time" foreignKey="TIME_ID" >
???
??? <Hierarchy? hasAll="false" primaryKey="TIME_ID" >
??????????? <Table name="TB_TIME" />
??????????? <Level name="year" column="THE_YEAR" uniqueMembers="false" />
??????????? <Level name="month" column="THE_MONTH" uniqueMembers="false" />
??????? </Hierarchy>
??? </Dimension>???????
???
??? <Measure name="Salary" column="SALARY" aggregator="sum" />
??? </Cube>
</Schema>
?
文件路徑為mywebapp/WEB-INF/mondriantest.xml
2
.
4
利用
MDX
查詢
mywebapp/mondriantest.jsp
1 <%@ page import="mondrian.olap.*"%>
<%
2 Connection connection =
? DriverManager.getConnection
("Provider=mondrian;????????????????
?Jdbc=jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:dbname;
JdbcUser=dbuser;????????????????????????????????????
?JdbcPassword=dbpasswd;???????????????????????????????
Catalog=file:///c:/Tomcat4.1/webapps/mywebapp/WEB-INF/mondriantest.xml;
JdbcDrivers=oracle.jdbc.driver.OracleDriver;",null,false);????
3 String queryStr=
"select {[Measures].[Salary]} ON COLUMNS,
{[Employee].[employeeId].Members} ON ROWS
from CubeTest ";
?
4 Query query =connection.parseQuery(queryStr);
5 Result result = connection.execute(query);
out.println("get result");
%>
2
.
5
運(yùn)行
這時啟動to
mcat,
在瀏覽器地址欄中輸入
http://localhost:8080/mywebapp/
mondriantest
.jsp
即可。
三、深入探討
3
.
1 API
mondrian
為客戶端應(yīng)用程序提供了API接口以進(jìn)行查詢。?而這些API對于任何用過JDBC的人都會覺得似曾相識的。主要的不同點是查詢語言的不同:Mondrian用的是MDX
('Multi-Dimensional eXpressions'),
而
JDBC
則用的是
SQL
。
和
JDBC
一樣,也是要經(jīng)過建立連接,形成查詢語句,執(zhí)行查詢得到結(jié)果集等幾個步驟的。
我們來看看
mondriantest.jsp
的代碼
第1行:import mondrian.olap.*
這是引入我們所需的類,下面要用到的DriverManager、Connection、Query、Result都在這個package內(nèi)。這個package一般位于mondrian.jar中。
第2行:Connection connection =
? DriverManager.getConnection
("Provider=mondrian;????????????????
?Jdbc=jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:dbname;
JdbcUser=dbuser;????????????????????????????????????
?JdbcPassword=dbpasswd;???????????????????????????????
Catalog=file:///c:/Tomcat4.1/webapps/mywebapp/WEB-INF/mondriantest.xml;
JdbcDrivers=oracle.jdbc.driver.OracleDriver;",null,false);?
通過DriverManager創(chuàng)建一個Connection的實例,建立起數(shù)據(jù)庫連接。
其中Jdbc=jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:dbname; 是設(shè)置數(shù)據(jù)庫的ip和庫名。JdbcUser=dbuser;? 設(shè)置數(shù)據(jù)庫用戶。JdbcPassword=dbpasswd;?? 設(shè)置用戶密碼。而
Catalog=file:///c:/Tomcat4.1/webapps/mywebapp/WEB-INF/mondriantest.xml;
就是設(shè)置MDX語句查詢要對應(yīng)的schema文件的路徑
第3行:String queryStr=
"select {[Measures].[Salary]} ON COLUMNS,
{[Employee].[employeeId].Members} ON ROWS
from CubeTest ";
形成MDX的查詢語句。MDX語句的形式和schema文件的設(shè)定是密切相關(guān)的,當(dāng)然schema文件的形成也是由數(shù)據(jù)庫結(jié)構(gòu)決定的。
第4行:Query query =connection.parseQuery(queryStr);對MDX語句進(jìn)行分析處理,是否符合schema文件定義、數(shù)據(jù)庫結(jié)構(gòu)和數(shù)據(jù)庫數(shù)據(jù)。
第5行:Result result = connection.execute(query);執(zhí)行查詢,得到結(jié)果集。
我們發(fā)現(xiàn)Query類似于JDBC的Statement,而Result則酷似于ResultSet。
3
.
2 schema
3
.
2
.
1
什么是
schema
schema
定義了一個多維數(shù)據(jù)庫。包含了一個邏輯模型,而這個邏輯模型的目的是為了書寫
MDX
語言的查詢語句。這個邏輯模型實際上提供了這幾個概念:
Cubes,
維度(
Dimensions
),
層次(
Hierarchies
),級別(
Levels
),和成員(
Members
)。
而
schema
文件就是編輯這個
schema
的一個
xml
文件。在這個文件中形成邏輯模型和數(shù)據(jù)庫物理模型的對應(yīng)。
3
.
2
.
2 schema
的邏輯結(jié)構(gòu)
3
.
2
.
2
.
1 Cube
一個
Cube
是一系列維度
(Dimension)
和度量
(Measure)
的集合區(qū)域。在
Cube
中,
Dimension
和
Measure
的共同地方就是共用一個事實表。
例:
<Cube name="CubeTest">
??? <Table name="TB_SALARY" />
?? …….
</Cube>
<Table>
標(biāo)簽確定了所用的事實表的表名。
3
.
2
.
2
.
2 Measure
一個度量,簡單的說,就是要被計算的值。
例:
<Measure name="Salary" column="SALARY" aggregator="sum" />
<Measure>
標(biāo)簽有
3
個必要的屬性
name
(度量名),
column
(在事實表中的字段名)
, aggregation
(聚合所用的方法)。
3
.
2
.
2
.
3 Dimenesion
而維度一般有其相對應(yīng)的維度表。
例:
<Dimension name="Time" foreignKey="TIME_ID" >
??????? <Hierarchy? hasAll="false" primaryKey="TIME_ID" >
??????????? <Table name="TB_TIME" />
??????????? <Level name="year" column="THE_YEAR" uniqueMembers="false" />
??????????? <Level name="month" column="THE_MONTH" uniqueMembers="false" />
??????? </Hierarchy>
</Dimension>
一般Dimesion包含層次(Hierarchy),而hierarchy是由級別(Level)組成。
<Dimension>
標(biāo)簽的foreignKey是事實表中的字段,<Hierarchy>標(biāo)簽的primaryKey是維度表中的字段,通過這種方式把事實表和維度表關(guān)聯(lián)起來。<Hierarchy>標(biāo)簽下的<Table>標(biāo)簽就指明了維度表名。而若干個Level對應(yīng)著維度表的若干字段。
3
.
3 MDX
語言
MDX
是為了查詢多維數(shù)據(jù)的,而SQL是為了查詢關(guān)系數(shù)據(jù)庫的。而Mondrian所涉及到的一些MDX概念、MDX語法以及系統(tǒng)定義的MDX函數(shù)和微軟的MDX十分接近,差別微小。完全可以參考微軟的幫助文檔進(jìn)行學(xué)習(xí)。在此就不在贅述。
四、結(jié)語
Mondrian
作為基于java的OLAP引擎,而且是開源的項目,為那些基于java的項目而要脫離微軟構(gòu)架但又不得不對大量數(shù)據(jù)進(jìn)行分析的項目又提供了一種可行的方案。希望它也能象
蒙得里安?皮特對抽象藝術(shù)的發(fā)展產(chǎn)生影響一樣起到一定的作用。