数据仓库研究之二--mondrian入门

来源:互联网 发布:德国联邦网络管理局 编辑:程序博客网 时间:2024/05/16 16:19
Mondrian is an OLAP server written in Java. It enables you to interactively analyze very large datasets stored in SQL databases without writing SQL.
http://sourceforge.net/projects/mondrian/
Mondrian是一个开源项目。一个用Java写成的OLAP(在线分析性处理)引擎。它用MDX语言实现查询,从关系数据库(RDBMS)中读取数据。然后经过Java API用多维的方式对结果进行展示。多维数据中,维度(dimension),层次(Hierarchies),级别(Level)等概念很重要。

 

OLAP用了多维分析的技术。尽管关系型数据库所存储的所有数据都是以行和列的形式存在的,但一个多维数据集还是可以由轴(axes)和单元(cell)组成。

 

一.环境准备

create table tb_employee
(
     employee_id int ,
     employee_name varchar(10)
);

create table tb_time
(
    time_id int,
    the_year char(4),
    the_month char(2)
);

create table tb_salary
(
    employee_id int,
    time_id int,
    salary int
);


insert into tb_employee values(1,"Mr A");
insert into tb_employee values(2,"Ms A");
insert into tb_employee values(3,"Ms B");
insert into tb_employee values(4,"Ms C");

insert into tb_time values(1,"2007","1");
insert into tb_time values(2,"2007","2");
insert into tb_time values(3,"2007","3");
insert into tb_time values(4,"2007","4");
insert into tb_time values(5,"2007","5");
insert into tb_time values(6,"2007","6");

insert into tb_salary values(1,1,11);
insert into tb_salary values(1,2,13);
insert into tb_salary values(1,3,12);
insert into tb_salary values(1,4,20);
insert into tb_salary values(1,5,21);
insert into tb_salary values(1,6,21);
insert into tb_salary values(2,1,13);
insert into tb_salary values(2,3,12);
insert into tb_salary values(2,4,12);
insert into tb_salary values(3,1,12);
insert into tb_salary values(3,2,13);
insert into tb_salary values(3,4,11);
insert into tb_salary values(4,1,11);
insert into tb_salary values(4,3,10);
insert into tb_salary values(4,5,10);

1.1
Windows + Tomcat 5.0 + MySQL 5.0.21

 

1.2
下载程序。Mondrianhttp://mondrian.sourceforge.net 可以下载,最早它是用MS Analyze Service的教程中FoodMart数据库作为demo的,那个是access的数据库。现在有了Platform-Independent的版本,例如下载mondrian-2.1.1-derby.zip 解压缩之后在lib目录里面有一个mondrian-embedded.war,把这个直接放到tomcat的webapps目录里面就能够看到mondrian的demo了。把这个war解开之后放到webapps里面去,并且目录把名字改为mondrian。启动tomcat,在浏览器输入http://localhost/mondiran 看到了demo。需要说明一下的是,mondrian的发布包含了Jpivot,用它来做展示层,所以不用再去单独下载Jpivot了。


1.3 数据库建表
在MySQL数据库里面建立数据库mt
二. 配置JSP、数据库

参见文章 JSP连接MySQL示例

三. mondrian测试

  需要说明的是mondrian使用了MS一样的MDX语言实现查询

3.1 编写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>

这个schema定义了一个cube,包含两个Dimension和一个Measure。
文件路径为webapps/mondrian/WEB-INF/queries/s.xml。

为了后面的测试方便,把文件放到了queries目录里面。

 

3.2 编写JSP

<%@ page import="mondrian.olap.*"%>
<%
Connection connection = DriverManager.getConnection("Provider=mondrian; Jdbc=jdbc:mysql://localhost/mt; JdbcUser=root; JdbcPassword=root; Catalog=file:///C:/Program Files/Tomcat 5.0/webapps/mondrian/WEB-INF/queries/s.xml; JdbcDriver=com.mysql.jdbc.Driver", null, false);

  String querystr = " select {[Measures].[Salary]} ON COLUMNS, {[Employee].[employeeId].Members} ON ROWS from CubeTest ";

  Query query=connection.parseQuery(querystr);
  Result result = connection.execute(query);
  out.println("get result");
  out.println(result);
%>

可以看到mondrian也使用jdbc来连接数据库的,其中要特别注意的是Catalog指名了schema的位置
文件路径webapps/mondrian/mt.jsp

 附加:
3.3 测试
(重新)启动Tomcat,在浏览器中输入 http://localhost:8080/mondrian/mt.jsp

可以看到显示的结果 get result,说明一切正常
四、深入探讨

4.1 API
mondrian为客户端应用程序提供了API接口以进行查询。 而这些API对于任何用过JDBC的人都会觉得似曾相识的。主要的不同点是查询语言的不同:Mondrian用的是MDX('Multi-Dimensional eXpressions'),而JDBC则用的是SQL。

和JDBC一样,也是要经过建立连接,形成查询语句,执行查询得到结果集等几个步骤的。

我们来看看mondriantest.jsp的代码

1行:import mondrian.olap.*

这是引入所需的类,下面要用到的DriverManager、Connection、Query、Result都在这个package内。这个package一般位于mondrian.jar中。

2行:Connection connection = DriverManager.getConnection("Provider=mondrian; Jdbc=jdbc:mysql://localhost/mt; JdbcUser=root; JdbcPassword=root; Catalog=file:///C:/Program Files/Tomcat 5.0/webapps/mondrian/WEB-INF/queries/s.xml; JdbcDriver=com.mysql.jdbc.Driver", null, false);

通过DriverManager创建一个Connection的实例,建立起数据库连接。

其中Jdbc=jdbc:mysql://localhost/mt 是设置数据库的ip和库名。JdbcUser=root; 设置数据库用户。JdbcPassword=root;   设置用户密码。而

Catalog=file:///C:/Program Files/Tomcat 5.0/webapps/mondrian/WEB-INF/queries/s.xml; 就是设置MDX语句查询要对应的schema文件的路径

3行:String queryStr=

"select {[Measures].[Salary]} ON COLUMNS,

{[Employee].[employeeId].Members} ON ROWS

from CubeTest ";

形成MDX的查询语句。MDX语句的形式和schema文件的设定是密切相关的,当然schema文件的形成也是由数据库结构决定的。

4行:Query query =connection.parseQuery(queryStr);对MDX语句进行分析处理,是否符合schema文件定义、数据库结构和数据库数据。

5行:Result result = connection.execute(query);执行查询,得到结果集。

我们发现Query类似于JDBC的Statement,而Result则酷似于ResultSet。

4.2 schema

4.2.1什么是schema

schema定义了一个多维数据库。包含了一个逻辑模型,而这个逻辑模型的目的是为了书写MDX语言的查询语句。这个逻辑模型实际上提供了这几个概念:Cubes,维度(Dimensions), 层次(Hierarchies),级别(Levels),和成员(Members)。

而schema文件就是编辑这个schema的一个xml文件。在这个文件中形成逻辑模型和数据库物理模型的对应。

4.2.2 schema的逻辑结构

4.2.2.1 Cube

一个Cube是一系列维度(Dimension)和度量(Measure)的集合区域。在Cube中,Dimension和Measure的共同地方就是共用一个事实表。

例:

<Cube name="CubeTest">

    <Table name="TB_SALARY" />

   …….

</Cube>

<Table>标签确定了所用的事实表的表名。

4.2.2.2 Measure

一个度量,简单的说,就是要被计算的值。

例:

<Measure name="Salary" column="SALARY" aggregator="sum" />

<Measure>标签有3个必要的属性name(度量名),column(在事实表中的字段名), aggregation(聚合所用的方法)。

4.2.2.3 Dimenesion

而维度一般有其相对应的维度表。

例:

<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>标签的foreignKey是事实表中的字段,<Hierarchy>标签的primaryKey是维度表中的字段,通过这种方式把事实表和维度表关联起来。<Hierarchy>标签下的<Table>标签就指明了维度表名。而若干个Level对应着维度表的若干字段。

4.3 MDX语言

MDX是为了查询多维数据的,而SQL是为了查询关系数据库的。而Mondrian所涉及到的一些MDX概念、MDX语法以及系统定义的MDX函数和微软的MDX十分接近,差别微小。完全可以参考微软的帮助文档进行学习。在此就不在赘述。

五、结语

Mondrian作为基于java的OLAP引擎,而且是开源的项目,为那些基于java的项目而要脱离微软构架但又不得不对大量数据进行分析的项目又提供了一种可行的方案。

 

JSP连接MySQL示例

下载mysql驱动程序(Mysql JDBC Driver)
http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.0.5.tar.gz/from/pick

  解压后,把里面的mysql-connector-java-5.0.5-bin.jar文件复制到你的tomcat/common/lib下,重启Tomcat,jsp连接mysql的环境就完成。
 
设MySQL中有数据库jsptest
 
create table t (fiel_name varchar(20),v int);
 
下面是访问数据库的示例程序

<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
String url ="jdbc:mysql://localhost/jsptest?user=***&password=***&useUnicode=true&characterEncoding=GB2312" ;
Connection conn= DriverManager.getConnection(url);
Statement stmt=conn.createStatement();
String query="select * from t";
ResultSet rs=stmt.executeQuery(query);
while(rs.next())
{
        String s=rs.getString("field_name");//字段不是字符型的话就不能用getString,根据字段类使用getBoolean等等
        int i=rs.getInt("v");
        out.println(s+" "+i+"<br>");
}
%>
</body>
</html>


 


<%@ page import="mondrian.olap.*"%>
<%
Connection connection = DriverManager.getConnection("Provider=mondrian; Jdbc=jdbc:mysql://localhost/mt; JdbcUser=root; JdbcPassword=root; Catalog=file:///C:/Program Files/Tomcat 5.0/webapps/mondrian/WEB-INF/queries/s.xml; JdbcDriver=com.mysql.jdbc.Driver", null, false);

  String querystr = " select {[Measures].[Salary]} ON COLUMNS, {[Employee].[employeeId].Members} ON ROWS from CubeTest ";

  Query query=connection.parseQuery(querystr);
  Result result = connection.execute(query);
  out.println("get result");
  out.println(result);
%>

原创粉丝点击