Mondrian + JPivot环境配置和演示

本文主要讲解ROLAP,以及ROLAP的实现Mondrian的使用和部署问题。目前网上关于Mondrian部署的帖子较少,连官网也是若干年前的版本,因此,开贴记录一下Mondrian在使用上的一些坑,关心Mondrian的使用请直接移步第二章。

1.OLAP简介

1.1什么是OLAP

OLAP系统,英文为OnLine Analytical Processing,中文为联机分析处理系统,它在数据分析决策方面为用户或“知识工人”提供服务,以不同的格式组织和提供数据,满足不同用户的形形色色的需求。与之相对的为OLTP(Online Transaction Processing,联机事务处理)系统,该系统主要用于单位的大部分日常操作,如购物、库存、制造、银行、工资、注册、记账等。

OLAP和OLTP的主要区别如下:

  • 用户:OLTP是面向顾客的,用于事办员、客户和信息技术专业人员的事务和查询处理。OLTP是面向市场的,用于知识工人(包括经理、主管和分析人员)的数据分析。
  • 数据内容:OLTP系统管理日常的、琐碎的数据,而这种数据一般很难用于决策。OLAP系统管理大量的历史数据,提供汇总和聚集机制,并在不同的粒度层上存储和管理系统。这些特点使得数据更容易用于有根据的决策。
  • 数据库设计:通常,OLTP系统采用实体-联系(ER)数据模型和面向应用的数据库设计。而OLAP系统通常采用星形或雪花模型和面向主题的数据库设计。
  • 视图:OLTP系统主要关注一个企业或部门内部的当前数据,而不涉及历史数据或不同单位的数据。相比之下,由于单位的演变,OLAP系统尝尝跨越数据库模式的多个版本。OLAP系统还处理来自不同单位的信息,以及由多个数据库集成的信息。
  • 访问模式:OLTP系统的访问主要由短的原子事务组成。这种系统需要并发控制和恢复机制。然而,对OLAP系统的访问大部分是只读操作,大多数是复杂的查询。

OLTP和OLAP的主要区别之一在于数据库的选择,由于OLTP系统是面向顾客的、需要并发控制和恢复机制,因此OLTP系统往往采用关系数据库,如MySQL、Oracle数据库等。而OLAP系统一般是只读的、大量历史数据的汇总和聚集,因此OLAP往往使用数据仓库。

宽泛地讲,数据仓库是一种数据库,它与单位的操作数据库分别维护。数据仓库系统允许将各种应用系统集成在一起,为统一的历史数据分析提供坚实的平台,对信息处理提供支持。面向主题的、集成的、时变的、非易失的是数据仓库的主要特征,也是将数据仓库与其他数据存储系统(如关系数据库系统、事务处理系统和文件系统)相区别。

  • 面向主题的(subject-oriented):数据仓库围绕一些重要主题,如顾客、供应商、产品和销售组织,关注决策者的数据建模与分析,拍除对于决策无用的数据,提供特地主题的简明视图。
  • 集成的(integrated):构造数据仓库通常是将多个异构数据源,如关系数据库、一般文件和联机事务处理记录集成在一起。
  • 时变的(time-variant):数据存储从历史的角度提供信息。数据仓库中的关键结构都隐式或显示地包含时间元素。
  • 非易失的(nonvolatile):数据仓库不需要事务处理、恢复和并发控制机制。通常,它只需要两种数据访问操作:数据的初始化装入和数据访问。

通常,数据仓库采用三层体系结构:

1.2 为什么需要使用分离的数据仓库

分离的主要原因是有助于提高两个系统的性能。操作数据库是为已知的任务和负载设计的。另一方面,数据仓库的查询通常是复杂的,涉及大量数据在汇总级的计算,可能需要特殊的基于多维视图的数据组织、存取方法和实现方法。在操作数据库上处理OLAP查询,可能会大大降低操作任务的性能。此外,操作数据库支持多事务的并发处理,需要并发控制和恢复机制,以确保一致性和事务的鲁棒性。通常,OLAP查询只需要对汇总和聚集数据记录进行只读访问。最后,数据仓库与操作数据库分离是由于这两种系统中数据的结构、内容和用法都不相同。

1.3 OLAP服务器的结构:ROLAP、MOLAP和HOLAP

用于OLAP处理的数据仓库服务器的实现包括了ROLAP(关系OLAP)、MOLAP(多维OLAP)和HOLAP(混合OLAP),ROLAP服务器是一种中间服务器,介于关系的后端服务器和客户前端工具之间,它们使用关系的或扩充关系的DBMS存储并管理数据仓库数据,而OLAP中间件支持其余部分,相应的实现有Mondrian等;MOLAP服务器通过基于数组的多维存储引擎,支持数据的多维视图,它们将多维视图直接映射到数据立方体数组结构。使用数据立方体的优点是能够对预计算的汇总数据快速索引,相应的实现有Cognos,SSAS,Kylin等;HOLAP服务器结合ROLAP和MOLAP技术,得益于ROLAP较大的可伸缩性和MOLAP的快速计算,比如微软的SQL Server2000。它们的区别的表格如下:

名称描述细节数据存储位置聚合后的数据存储位置代表
ROLAP基于关系数据库的OLAP实现关系型数据库关系型数据库Mondrian
MOLAP基于多维数据组织的OLAP实现数据立方体数据立方体Cognos,SSAS,Kylin
HOLAP基于混合数据组织的OLAP实现关系数据库数据立方体SQL Server

个人认为上面的几种方式没有绝对的优劣之分,选择哪种结构还是和具体的应用有关。 

2.Mondrian+JPivot

Mondrian是ROLAP的实现之一,它是搭配构建数据立方体的XML文件,根据访问的MDX语句动态查询数据库,在内存中存储数据立方体,并返回结果,因此,Mondrian对内存的要求较高。

官网地址:https://mondrian.pentaho.com/documentation/olap.php。通过查看官网,你会发现,Mondrian是提供了war包的,然而,官网有关于[安装]的内容应该滞后若干个版本,也就是说,单纯的Mondrian只是提供了jar包,如果想要使用线上展示结果的功能,需要搭配JPivot一起使用,JPivot提供war包,它需要Mondrian的jar包,然后配合jsp代码来实现网页的可视化。有关于Mondrian和JPivot的环境配置,请参考参考文章的第三个Mondrian + JPivot 环境配置。从https://pan.baidu.com/s/1zkSyZJkTGabEFwcfsktDCw 下载 mondrian server.rar , test-mondrian.rar。本小节主要讲解JPivot的粗略的运行方式。

test-mondrian.rar为控制台运行的方式,运行Main.java,输出如下:

Axis #0:
{}
Axis #1:
{[Measures].[Amount]}
Axis #2:
{[AccessTime].[AllTime], [WebsiteNum].[AllSite], [UserIP].[AllIP]}
Row #0: 278

 Main.java中的MDX语句是查询所有访问记录的总次数,查询结果为278。但是控制台查询的弊端在于不够直观,比如MDX语句为:

SELECT {[Measures].[Unit Sales], [Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS,
{descendants([Time].[1997].[Q1])} ON ROWS
FROM [Sales] WHERE [Gender].[F]

 旨在查询1997年第一季度的所有月份,女性的消费记录,输出如下:

Axis #0:
{[Gender].[All Genders].[F]}
Axis #1:
{[Measures].[Unit Sales]}
{[Measures].[Store Sales]}
{[Measures].[Profit]}
Axis #2:
{[Time].[1997].[Q1]}
{[Time].[1997].[Q1].[February]}
...
{[Time].[1997].[Q1].[March].[15].[Sunday]}
Row #0: 32,910
Row #0: 69,798.23
Row #0: $41,976.46
Row #1: 10,266
Row #1: 21,773.93
Row #1: $13,110.09
Row #2: 207
Row #2: 414.6
Row #2: $246.12
Row #3: 207
Row #3: 414.6
Row #3: $246.12
Row #4: 2,871
Row #4: 5,940.83
Row #4: $3,580.08
...
Row #109: 206
Row #109: 405.37
Row #109: $239.28

 那么控制台方式的输出方式的缺点则更加凸显,接下来,则开始讲解JPivot。

参考文章3已经给出了一个简单的demo,该示例为上述输出的jsp版本。接下来主要分析,在jpivot.war的基础上,如何自行添加相关的jsp页面。这里假设tomcat已经处于运行之中,那么输入http://127.0.0.1:8080/jpivot/index.jsp,页面如下:

在上述页面中,AccessInfo为压缩包中的Sample Demo,FoodMart3为第二个MDX语句的输出结果,首先观察index.jsp,该文件在webapps\jpivot文件夹下,打开:

...
<ul>
  <li><a href="testpage.jsp?query=mondrian">Slice and Dice with two hierarchies</a></li>
  <li><a href="testpage.jsp?query=fourhier">...and with four hierachies</a></li>
  <li><a href="test/param3.jsp?query=mondrian">Dynamic parameters with Mondrian</a></li>
  <li><a href="testpage.jsp?query=arrows">Arrows in Cells</a></li>
  <li><a href="testpage.jsp?query=colors">Colors in Cells</a></li>
  <li><a href="testpage.jsp?query=testquery">Test data</a></li>
  <li><a href="testpage.jsp?query=AccessInfo">AccessInfo</a></li>
  <li><a href="testpage.jsp?query=FoodMart3">FoodMart3</a></li>
  <li><a href="test/param1.jsp?query=testquery">Dynamic parameters with test data</a></li>
</ul>
...

 通过对比网页发现,<li><a href="testpage.jsp?query=AccessInfo">AccessInfo</a></li>为入口URL,那么接着打开testpage.jsp,第44行:

<%-- include query and title, so this jsp may be used with different queries --%>
<wcf:include id="include01" httpParam="query" prefix="/WEB-INF/queries/" suffix=".jsp"/>

prefix为前缀,suffix为后缀,再结合传入的query,整合起来就是 /WEB-INF/queries/AccessInfo.jsp,接着打开该文件:

<%@ page import="mondrian.olap.*"%>
<%@ page session="true" contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://www.tonbeller.com/jpivot" prefix="jp" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
 
<jp:mondrianQuery id="query01" jdbcDriver="com.mysql.jdbc.Driver" jdbcUrl="jdbc:mysql://localhost/jpivot" catalogUri="/WEB-INF/queries/AccessInfo.xml" jdbcUser="jpivot" jdbcPassword="jpivot" connectionPooling="false">
 
select NON EMPTY {[Measures].[Amount]} ON COLUMNS,
    NON EMPTY{([AccessTime].[AllTime], [WebsiteNum].[AllSite], [UserIP].[AllIP]) } ON ROWS
    from [AccessAnalysis]
</jp:mondrianQuery>

 可以发现,该文件就是Main.java文件的jsp实现方式,可视化展示查询结果:

JPivot还提供了诸如下钻、上卷,图表等功能,比如此时点击AllTime可以观察不同时间(注:我个人的数据库中的部分数据存在修改,与db.sql不同):

此时可以把AllTime关闭,点击AllIP可以擦好看不同IP的访问次数:

再点击AllSite,可以查看哪些IP访问了哪些网站:

点击显示图表,默认展示柱状图:

总结:Mondrian+JPivort是比较强大的ROLAP工具,尤其是JPivot可以以可视化的形式展示结果。本示例只是展示了Mondrian的冰山一角。后续我可能会发布一些细节的功能实现,比如以restful的形式提供功能等。

3.注意事项

3.1 JPivot MDX编辑框中文乱码和数据查询问题

在Mondrian中有两个有关于使用中文会遇到的坑,第一个就是在JPivot的MDX编辑界面时,输入的中文会乱码。这个问题我参考网上的并没有解决。。。

第二个则是我个人遇到的坑。目前互联网上有关Mondrian的连接一般是下面的流程:

package com.mondrian;

import java.io.PrintWriter;

import mondrian.olap.Connection;
import mondrian.olap.DriverManager;
import mondrian.olap.Query;
import mondrian.olap.Result;

public class Main {

	public static void main(String[] args) {
		String connectString = "Provider=mondrian;Jdbc=jdbc:mysql://127.0.0.1/FoodMart?user=root&password=root;Catalog=FoodMart3.xml;";
		Connection connection = DriverManager.getConnection(connectString,null);

        String mdx = "SELECT {[Measures].[Unit Sales], [Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS," +
				" {[Time].[1997].[Q1]} ON ROWS" +
				" FROM [Sales] WHERE [Gender].[Gender].[男]";
		
		Query query = connection.parseQuery(mdx);
		Result result = connection.execute(query);
		PrintWriter pw = new PrintWriter(System.out);
		result.print(pw);
		pw.flush();	
	}
}

FoodMart3.xml是官方提供的一个示例,其文件内容如下:

<?xml version="1.0"?>
<Schema name="FoodMart2">
    <Cube name="Sales">
        <Table name="sales_fact_1997"/>
        <!--维表 性别-->
        <Dimension name="Gender" foreignKey="customer_id">
            <Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
                <Table name="customer"/>
                <Level name="Gender" column="gender_zh" uniqueMembers="true"/>
            </Hierarchy>
        </Dimension>
        <!--维表 时间-->
        <Dimension name="Time" foreignKey="time_id">
            <Hierarchy hasAll="false" primaryKey="time_id">
                <Table name="time_by_day"/>
                <Level name="Year" column="the_year" uniqueMembers="true"/>
                <Level name="Quarter" column="quarter" uniqueMembers="false"/>
                <Level name="Month" column="the_month" type="String" uniqueMembers="false"/>
                <Level name="Week" column="week_of_year" uniqueMembers="false"/>
                <Level name="Day" column="the_day" type="String" uniqueMembers="false"/>
            </Hierarchy>
        </Dimension>
        <!--度量-->
        <Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###"/>
        <Measure name="Store Sales" column="store_sales" aggregator="sum" formatString="#,###.##"/>
        <Measure name="Store Cost" column="store_cost" aggregator="sum" formatString="#,###,00"/>
        <!--新定义的一个度量 Profit=[Store Sales] - [Store Cost]-->
        <CalculatedMember name="Profit" dimension="Measures" formula="[Measures].[Store Sales] - [Measures].[Store Cost]">
            <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
        </CalculatedMember>
    </Cube>
</Schema>

注:在FoodMart3.xml文件中,我所做的就是在FoodMart数据库中的customer表添加了一个gender_zh字段,其值可能是男或女。

首先是连接mysql数据库和数据立方体的配置文件,然后一个查询的MDX语句,最后则是输出。使用这种方法貌似没有问题,但是,此时输出会返回空:

Axis #0:
{[Gender].[All Genders].[男]}
Axis #1:
{[Measures].[Unit Sales]}
{[Measures].[Store Sales]}
{[Measures].[Profit]}
Axis #2:
{[Time].[1997].[Q1]}
Row #0: 
Row #0: 
Row #0: 

 其中的一个主要原因,也就是我遇到的原因,就是在使用jdbc连接mysql数据库的时候,没有指定编码方式,因此connectString应该改为:

String connectString = "Provider=mondrian;Jdbc=jdbc:mysql://127.0.0.1/FoodMart?useUnicode=true&characterEncoding=utf-8&user=root&password=root;Catalog=FoodMart3.xml;";

此时输出正常:

Axis #0:
{[Gender].[All Genders].[男]}
Axis #1:
{[Measures].[Unit Sales]}
{[Measures].[Store Sales]}
{[Measures].[Profit]}
Axis #2:
{[Time].[1997].[Q1]}
Row #0: 33,381
Row #0: 69,830.12
Row #0: $41,899.65

如果是在JPivot中使用的话,则需要在jsp文件的<jp:mondrianQuery>的jdbcUrl添加userEncoding和characterEncoding即可:

<jp:mondrianQuery id="query01" jdbcDriver="com.mysql.jdbc.Driver" jdbcUrl="jdbc:mysql://127.0.0.1/ren_db?useEncoding=true&characterEncoding=utf-8" catalogUri="/WEB-INF/queries/FoodMart3.xml" jdbcUser="root" jdbcPassword="root" connectionPooling="false">

SELECT {[Measures].[Unit Sales], [Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS,
 {[Time].[1997].[Q1]} ON ROWS FROM [Sales] WHERE [Gender].[Gender].[男]
</jp:mondrianQuery>

3.2 Mondrian的版本问题

 目前官方同时维护的Mondrian版本有3.x、4.x和8.x。在github地址也并没有过多提及相关的区别,在mondrian-rest(Mondrian-rest使用spring boot实现了Mondrian的restful API)中关于Mondrian版本的部分介绍为:

Initial development of mondrian-rest supported version 4.x of the Mondrian library. However, Mondrian 4.x does not appear to be under active development by the core Mondrian maintainers, so we have abandoned it as a dependency. The last version of mondrian-rest that supports version 4.x schemas is version 1.5.0. PRs for the 1.x line of mondrian-rest will be considered, but active development of mondrian-rest by the core committers is focused on Mondrian 8.x (and, at some point, version 9.x). There are significant schema differences between 4.x and 8.x+, however for the most part, the mondrian-rest API is consistent between mondrian-rest v2.x and v1.x.

内容大致是:

Mondrian-rest的初始开发支持Mondrian的4.x版本。但是,mondrian4.x似乎并没有被核心维护人员积极开发,所以我们放弃了它作为一个依赖项。支持版本4.x架构的mondrian-rest的最后一个版本是版本1.5.0。mondrian-rest的积极开发主要集中在Mondrian的8.x版本(在某些情况下,版本9.x)。4.x和8.x+之间存在显著的模式差异,但是在大多数情况下,mondrian-rest api在mondrian-rest v2.x和v1.x之间是一致的。 

3.3 可视化

Mondrian官方推荐使用JPivot实现OLAP的可视化,虽然JPivot在交互上较为强大,但是我个人认为它在可视化和使用上要略差,而且JPivot官网的war包很久没有更新了,因此,这里我个人推荐使用Saiku来实现Mondrian的可视化。有关于Saiku的快速上手,我推荐这个资源:saiku2.6解压我的Tomcat资源可以直接运行,以及这个帖子:saiku2.6完整版(运行Tomcat可以直接使用)。俗话说,百闻不如一见,通过这个资源和配套的这个帖子可以快速上手Saiku,在大致了解了saiku的功能后可以考虑是否使用saiku。

4.参考文章

  1. 浅谈ROLAP、MOLAP和HOLAP区别

  2. OLTP与OLAP的关系是什么?

  3. Mondrian + JPivot 环境配置

  4. 《数据挖掘 概念与技术》

  5. MDX语句(初学者)

  6. Mondrian使用教程

  7. mysql 中文java_java链接mysql 中文乱码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值