现在大家比较公认的商业智能系统分为报表、OLAP、数据仓库、数据挖掘和即席查询五大块,本身商业智能系统也只是一个比较新的概念,也许随着技术和应用的发展还会扩充出来很多模块。本文就基于开源BI平台Openi的数据仓库系统,进行整体设计及开发,就其中比较热门的技术,如OLP、数据仓库等进行初步的控告,以期起到一个抛砖引玉的作用。
一、 开源的BI平台
商业智能也称作BI是英文单词Business Intelligence的缩写。商业智能通常被理解为将企业中现有的数据转化为知识,帮助企业做出明智的业务经营决策的工具。这里所谈的数据包括来自企业业务系统的订单、库存、交易账目、客户和供应商等来自企业所处行业和竞争对手的数据以及来自企业所处的其他外部环境中的各种数据。而商业智能能够辅助的业务经营决策,既可以是操作层的,也可以是战术层和战略层的决策。为了将数据转化为知识,需要利用数据仓库、联机分析处理(OLAP)工具和数据挖掘等技术。因此,从技术层面上讲,商业智能不是什么新技术,它只是数据仓库、OLAP和数据挖掘等技术的综合运用。
从国内企业和政府部门的信息化建设发展来看,从最初的各类MIS系统到近几年流行的ERP、CRM等,用户的数据积累已达到了一定的程度,很多行业的用户面对越来越激烈的市场竞争,他们需要对自己的数据(用户、市场、产品)进行分析,挖掘出潜在的商机,降低公司的运作成本,这是BI和数据仓库类产品被市场看好、不断获得增长的根本原因!
在现有的市场中,对于BI类产品来说往往是与数据仓库整体解决方案相关联,一些国内的IT公司也正在把BI和数据仓库的结合作为行业的解决方案来推广到自己熟悉的领域。对于IT公司来说在ERP、CRM之后需要寻找新的利润增长点,BI和数据仓库的出现无疑是一个莫大的商机。
在商业智能系统出现之前,大家都是通过报表来展现数据库中的数据,报表有简单有复杂,当然报表只能静态的展现一部分数据,用户只能看到已经做好的报表,不能根据自己的需要重新构造报表。随着技术的发展,出现了OLAP分析,它能够让用户根据自己的想法对数据进行聚类、分类、钻取等操作,这样就很好的解决了报表不能动态展现的问题。之后随着数据仓库和数据挖掘技术的不断完善,大家都认为商业智能系统主要是分析数据,就把OLAP、数据仓库和数据挖掘归类到一起形成了BI系统,这三项确实能够体现Intelligence的概念。因此初期的BI系统都是只含有这三块,但是用户在使用一段时间后认为报表模块是必不可少的,因此都纷纷要求BI供应商将报表模块加进来,为什么会出现这种情况呢?因为虽然OLAP能动态展现数据,但是它主要还是侧重于决策者的分析,而中层领导更喜欢看到的是报表,他们需要掌握自己所分管部分的运营情况,报表则是最好的展现数据的方式,因此最后各BI厂商就将报表也加入到BI系统中去了,例如BO收购水晶报表,Hyperion收购Brio等都是BI厂商收购报表厂商来完善自己的报表功能。
下面列出相对成熟和完整,并且有借鉴意义的开源BI套件,而本文中的仓库系统的设计及开发采用就是其中的Openi这种开源的BI平台。
(1)、Bizgres
为GreenPlum公司主导的开源项目,和Sun公司达成合作关系。Bizgres为BI应用而对PostgreSQL做了优化,提高了大负荷的并行计算能力,在BI环境中,相对于普通的关系型数据库具有卓越的数据处理性能。Bizgres的数据库平台可以和KETL和JasperReports进行整合,从而形成一个BI套件。
(2)、Openi
是一个Java开发的Web应用,能对OLAP服务器、关系数据库和数据挖掘服务器进行分析和报表展示,非常易于使用和部署,界面美观友好,后续还将支持数据挖掘和ETL等。
(3)、Pentaho
是一个以工作流为核心的、强调面向解决方案而非工具组件的BI套件,整合了多个开源项目,目标是和商业BI相抗衡。它包括。由上可见Pentaho是一个很完善的BI解决方案。Pentaho偏向于与业务流程相结合的BI解决方案,侧重于大中型企业应用。
(4)、SpagoBI
SpagoBI 集成了Mondrain和JProvit,能够通过OpenLaszlo产生实时报表。SpagoBI使用java开发,不依赖于具体的操作系统,有很强的扩展能力。根据其Roadmap可以看出,SpagoBI将融入更多的BI功能,甚至BI之外的功能。
二、 系统设计
1.系统体系结构
该系统基与多层体系结构设计,其中包括:
WEB客户端层;
WEB服务器层;
数据持久层。
2.系统数据流程
下面我们来介绍一下数据仓库系统的数据流程,以此来让用户更好的把握产品的整体架构和功能原理。下图为系统的数据流程与相关功能关系图。
从上面的图中我们可以看到,数据仓库系统系统数据有两类:业务数据和多维数据。业务数据由业务系统产生,经过一系列处理并放到数据仓库中的关系数据库。由于它直接来源于业务系统,因此,它真实反映了业务系统的明细数据,由于其数据量有可能很大,访问时需要考虑要消耗的资源。
多维数据是系统从数据仓库中经过汇总、统计而产生的。它通过采用多维结构和将一些数据预先进行了统计等预处理操作,对原始数据进行重新组合,来实现灵活而快速的数据访问。
3.系统开发框架
4.多维分析主题(CUBE)
存储用户所关心的某一分析主题的相关数据,其下包括多个维(分析角度)和一或多个指标。例如一个名为Sales的多维分析主题通常会包括时间、产品、门店、顾客以及指标如销售额、成本等等。
(1)、维
维度是描述事物特征的一个角度。例如门店销售情况需要分析商品销售的时间、地点、商品名等。这里的时间、地点、商品名就是门店销售情况的分析维度。
(2)、维结构
维度是有结构的,每个维度可以由若干个层次组成的,例如时间维度,可以由四个层次组成:年、季、月、日,每一个层次又由若干个维成员组成。
(3)、维成员
组成维度的子成员,如时间维度可以由其维成员2003年、2004年、2005年等具体年份来构成。
(4)、分析主题
用户所关注业务的一个考核方面:如门点销售情况分析,仓库库存情况分析等等。
(5)、指标
一个特殊的维度。它的成员都是数值型的,用来描述维度或维成员的的量属性,例如门店销售情况分析中的销售额 ,商品成本等。
(6)、多维分析报表
多维分析报表中的数据来源于一个多维分析主题。多维分析主题能将同一个分析主题所涉及到的数据,即影响因素“维”和衡量因素“指标”集中存储并且部分预先统计出来,多中角度,对从原始数据中转化出来的、能够真正为用户所理解的、并真实反映企业特征的信息,进行快速、一致、交互地存取,从而获得对数据的更深入地了解。多维分析报表的优点在于能够摆脱业务系统数据及数据结构的限制,真正地以客户的思维逻辑来生成报表。
三、 系统开发
1 .程序运行框架
本系统主要基于Spring Web MVC框架开发,
Action配置文件为WEB-INF"springapp-servlet.xml,
View配置文件为WEB-INF"classes"springapp-views.properties
程序运行框架图如图所示:
2 .WCF组件
本系统对OLAP的操作主要基于JPivot组件实现,界面展现主要采用WCF组件进行渲染,本节对JPivot组件和WCF组件的使用进行详细介绍。
WCF是一个JSP 自定制的标签库,它主要通过XSLT对XML进行渲染,创建、展现和验证HTML表单。特别地,JPivot组件通过Renderable接口中的render方法生成组件的XML描述信息,再借助于WCF的Render标签可以将XML描述信息转换为HTML发布到用户界面上。以下对WCF部分标签的用法分别予以介绍。
(1).form
此组件采用XML文件的方式来创建HTML表单,该组件在设计阶段并不中见,必须通过WCF render标记进行渲染后方可见。XML文件的格式如下:
示例:
<xform style="twocolumn">
<title value="Form Demo">
<imgButton label="Cancel" .../>
</title>
<textField type="int" modelReference="intValue" label="Count" .../>
<checkBox modelReference="nestedBean.boolValue" label="Check Me" .../>
</xform>
而它的数据绑定而言,关联到了相关的JavaBean。通过modelReference属性来对bean属性注入值。当然modelReference可以包含EL表达式。
示例:
<jsp:useBean id="testbean" class="com.tonbeller.wcf.form.TestBean" scope="session" />
<wcf:form id="formcomp" xmlUri="/WEB-INF/formdemo.xml" model="#{testbean}"/>
<form action="formdemo.jsp" method="POST" id="form01">
<wcf:render ref="#{formcomp}" xslUri="/WEB-INF/wcf/wcf.xsl" xslCache="true"/>
</form>
示例:
<xform style="twocolumn">
<title value="fmt:fetch.title.from.resource.bundle">
<imgButton id="cancel" src="wcf/form/cancel.png" action="revert" label="Cancel" forward="tabledemo.jsp" handler="com.tonbeller.wcf.form.ButtonHandler"/>
</title>
<!-- Text control -->
<textField id="string" type="string" modelReference="stringValue" label="Text:" value="" title="please enter some text"/>
<textField id="int" type="int" modelReference="intValue" label="Integer:" value="" title="please enter an integer"/>
<textField id="double" type="double" modelReference="doubleValue" label="Decimal number:" value="" title="please enter a decimal number"/>
<textField id="date" type="date" modelReference="dateValue" label="Date:" value="" title="please enter a date"/>
<textField id="dateTime" type="dateTime" modelReference="dateTimeValue" label="Date/Time:" value="" title="please enter a date/time"/>
<!-- Password control -->
<password id="password" type="string" modelReference="password" label="Password:" value=""/>
<!-- Text area -->
<textArea id="textarea" rows="7" cols="40" type="string" modelReference="textArea" label="Text area:" value="This is a text area"/>
<checkBox id="checkbox1" modelReference="checkBox1" label="check box 1"/>
<checkBox id="checkbox2" modelReference="checkBox2" label="check box 2"/>
<!-- ListBox, single selection -->
<listBox1 id="list1" type="int" modelReference="list1" label="List, single selection:">
<listItem id="list1.1" value="1" label="list item 1"/>
<listItem id="list1.2" value="2" label="list item 2"/>
<listItem id="list1.3" value="3" label="list item 3"/>
<listItem id="list1.4" value="4" label="list item 4"/>
</listBox1>
<!-- ListBox, multiple selection -->
<listBoxN id="listN" type="int" modelReference="listN" label="List, multiple selection:">
<listItem id="listN.1" value="1" label="list item 1"/>
<listItem id="listN.2" value="2" label="list item 2"/>
<listItem id="listN.3" value="3" label="list item 3"/>
<listItem id="listN.4" value="4" label="list item 4"/>
</listBoxN>
<!-- ListBox, single selection, dynamic item list -->
<listBox1 id="listbox" type="int" modelReference="dynList" label="List, dynamic content:" handler="com.tonbeller.wcf.form.TestItems"/>
<label label="This is a label" value="value attribute goes here"/>
<label label="Dynamic label (content from TextArea)" modelReference="textArea"/>
<radioButton id="radio1" modelReference="radioButton1" group-id="group1" label="radio button 1"/>
<radioButton id="radio2" modelReference="radioButton2" group-id="group1" label="radio button 2"/>
<buttons>
<button id="cancel" action="revert" label="Cancel" forward="tabledemo.jsp" handler="com.tonbeller.wcf.form.ButtonHandler"/>
<button id="revert" action="revert" label="Revert" handler="com.tonbeller.wcf.form.ButtonHandler"/>
<button id="validate" action="validate" label="Validate" handler="com.tonbeller.wcf.form.ButtonHandler"/>
<button id="ok" action="validate" label="OK" forward="tabledemo.jsp" handler="com.tonbeller.wcf.form.ButtonHandler"/>
</buttons>
</xform>
3.JPivot组件
JPivot - 是一个JSP 自定制的标签库,可以绘制一个OLAP表格和图表。用户可以执行典型的OLAP操作,如上钻、下钻、切片、和切块等。JPviot组件不能直接产生界面输出,但Pviot所有的可发布的组件都实现了Renderable接口,所有组件的输出信息都是通过Renderable接口中的render方法生成的,然后由WCF标签库的render标签调用JPivot组件的render方法将组件信息输出到界面上。以下对JPivot部分组件的用法分别予以介绍。
(1).chooseQuery
采用queryName属性来创建查询内容。
示例:
<jp:mondrianQuery id="query01" queryName="name1">
SELECT ...
</jp:mondrianQuery>
<jp:mondrianQuery id="query01" queryName="name2">
SELECT ...
</jp:mondrianQuery>
...
<jp:chooseQuery id="query01" queryName="name1"/>
(2).clickable
使所有的维度成员或级别可以点击,例如产生一个链接。产生的URL地址包含成员的唯一名称。当然,它的动作依赖于sessionParam属性,当它存在时,在新页面展示之前,参数值将写进com.tonbeller.jpivot.param.SessionParamPool。当不存在时,参数值将通过编码附加在超级链接后面。
示例:
<jp:mondrianQuery ...>
select .. from Sales
<jp:clickable urlPattern="/otherpage.jsp?param={0}" uniqueName="[Customers]"/>
<jp:clickable page="/yetotherpage.jsp" uniqueName="[Products].[Category]" sessionParam="Category"/>
</jp:mondrianQuery>
四、 系统效果
1. 设置数据源和多维模型
2. 浏览报表