Mondrian入门介绍之schema manager(二)


3 编写Schema文件test.xml

  在利用Mondrian进行多维分析过程中需要十分注意Schema文件的编写。Schema文件是对数据库中表的多维模型定义,所以有些选项要和数据库中表的定义保持一致,更为重要的是Schema文件的设计的好坏直接影响到多维查询的效率,Mondrian在schema文件定义的过程中提供了很多配置选项,可以对多维查询进行优化。下面是基于数据库表的一个test.xml:

  在test.xml中定义了一个名为CubeTest的立方体,这个立方体对应的事实表是tb_salary,定义了两个维度Employee和Time,这两个维度分别有一个层次,对应的维度表分别是tb_employee和tb_time,employeeid层次有一个级别,而time层次有两个级别。在事实表中用employeeid和timeid连接到这两个维表,该星型模式如图4所示:

图4

  4 编写测试类

  可以构建一个简单的查询与结果输出:

图五

  控制台输出的结果应为:

     

  5 测试类的流程

  从测试类可以看出Mondrian的api的确与Jdbc有很多相似之处,从构建查询到输出结果主要完成四个步骤:

  (1) 初始化Connection,初始化时传入必要的参数。getConnection(str)中的str就是连接字符串,指定了数据库参数和jdbc驱动。

  (2) 生成一个String对象,用来保存MDX查询语句。

  (3) 生成一个Query对象,用来查询结果。

  (4) 生成一个Result对象,用来保存结果。

  其中Connection,Query,Result对象均是Mondrian自定义类型。

  3.2.2 Schema Manager

  1Connection初始化与Rolapschema

  测试类的第一个步骤初始化了Connection对象,Connection对象提供了Mondrian的入口,Connection对象有一个十分重要的成员变量schema,Connection初始化的大部分工作其实是在完成schema的初始化。在整体架构中,Connection初始化属于Session Manager的范畴,而Schema的初始化由Schema Manager专门完成。Connection对象中含有Schema对象,这也是Session Manager和Schema

  Manager存在紧密联系的原因。图5是初始化一个connection的时序图:

 图6

  Connection在Mondrian中定义为接口类型,RolapConnection实现了Connection接口,完成了实际初始化的过程。图6展示了类RolapConnection的部分方法和全部属性:

图7

  RolapConnection其中的一些属性与schema有很大的关联。datasource指定了连接数据源,如果在连接字符串里定义了jdbc参数,该属性可以为空。catalogUrl是test.xml的路径,schema的初始化是围绕xml文件展开的。schemaReader为其他对象提供了获取schema内部信息的渠道。

  RolapConnection的初始化最终会调用第二个构造方法。如果其schema参数为空,那么会调用RolapSchema.Pool.instance.get()方法,从这里开始,系统流程从Session Manager部分转到Schema Manger部分。Pool是RoalpSchema的内部类,Pool类利用Singleton模式维护了一个schema池,这样对于不同的connection,如果它们所用的xml文件是一样的,那么只用生成一个schema实例就可以满足需要,当xml文件很大时,shema池可以提高初始化效率。

  Mondrian提供了两种方式从schema池中取schema对象,一种是基于关键字的,一种是基于内容检查的。关键字key主要包含是xml文件路径、文件名和数据库连接参数,当采用这种方式时,schema池便是key与schema对象的映射,用key来访问schema对象。这一映射用java语言中的软引用技术实现和垃圾收集器之间的交互,最大限度上的利用内存同时又不影响垃圾收集过程。但是存在一个问题,那就是不同的key对应的xml文件的内容可能是一样的:可能同一个xml文件放在不同的路径下,也可能是xml文件名字不同但内容是一样的,在这种情况下,不同的key对应相同的schema对象,出现了对象冗余。基于内容检查的获取方式可以解决这一问题,它的实现思想是,用两个key来对应一个schema对象,一个key与上述的key完全一样,另一个key是对xml内容用md5加密后的字符串,取schema对象时,先将xml内容用md5加密,用得到字符串和映射中的所有key比较,如果字符串与映射中的某个key相同,说明对于该xml文件内容,映射中存在相应的schema对象,直接取就可以了,如果映射中没有一个key满足要求,说明该xml内容是第一次初始化,那么初始化对应的schema对象,并添加两个映射:key与schema对象的映射和md5字符串与schema对象的映射。在这里key与schema对象的映射并不是多余的,因为md5字符串可能为空。

  两种访问schema池的方法各有优劣,在实际应用中很难估计所使用的xml文件内容有多少是完全相同的。如果xml内容各不相同,第二种方式的效率反而会很低,不仅浪费了时间,而且还浪费了空间。基于内容检查方式Mondrian默认设置是关闭的,可以根据实际应用情况进行配置。

  2 schema对象的初始化

  schema对象的初始化是SchemaManager的主要功能。显然,当初始化第一个连接访问schema池的时候,schema池是空的,这个时候就涉及到schema对象的初始化,即对于一个xml文件,建立与之对应的schema对象,并把该schema对象放到schema池里面去。图7是shema对象初始化的时序图,较之connection初始化的时序图,更为详细了描述了schema部分的初始化过程:

图8

  RoalpSchema的类图如图8所示:

图9

  类图中列出了一个schema对象的主要属性和主要的初始化方法。结合时序图和类图,可以分析出schema初始化的大致流程:

  (1) RolapSchema的六参构造方法调用RolapSchema的四参构造方法,在Rolap四参构造方法中,初始化了internalConnection,主要是设置了internalConnection的datasource属性,如前面所述,datasource传递进来时可以为空,在初始化internalConnection时,如果传递进来的datasource为空,会根据传递进来的jdbc参数构造一个datasource,这个datasource至关重要,在生成数据库方言的时候要用到。此外,构造方法还初始化了几个重要的映射:如立方体名到立方体的映射、共享层次到阅读器的映射、共享层次名到层次的映射,当然此时的映射都为空。最后构造方法初始化了一个aggTableManager对象,用来管理聚集表。

  (2) RoalpSchema六参构造方法调用RolapSchema的成员函数Load(String,String)。Load(String,String)函数的主要作用是解析xml文件,以及将多维模型转换为MondrianDef定义的对象。Load(String,String)函数使用了EigenBase包,EigenBase是一个开源的数据管理系统,函数里面用EigenBase提供的xml解析器来解析xml文件。同时函数中利用apache提供的common包建立了虚拟文件系统,正是这个虚拟文件系统实现了不同的xml文件读取方式:比如从本地文件中读取或者从http协议读取。EigenBase为xml的解析提供了一套api,解析的方式是嵌套进行的。Mondrian中与EigenBase xml parser交互的类是MondrianDef,这个类用内部类的方式定义了所有的多维概念,解析过程中,xml节点转化为多维对象并建立彼此之间的联系。这些对象都被包含在xmlSchema对象之中。需要注意的是,MondrianDef定义的多维概念只能算做一种中间过渡的临时类型,因为此时只建立了立方体、维度、层次、级别、事实之间最基本的关系,没有考虑到数据的共享,函数的调用。

  (3) 在Load(String,String)方法中调用Load(MondrianDef.Schema)方法。Load(MondrianDef)方法主要做了两件事情:函数表对象的初始化,根据MondrianDef的多维对象生成最终的多维对象。在Load(MondrianDef.Schema)方法中初始化了RolapSchemaFunctionTable对象,RolapSchemaFunctionTable是RolapSchema的内部类,主要用来接收用户自定义函数的定义,这个自定义函数的定义来自与xml文件。调用RolapSchemaFunctionTable对象的intialize()函数时,初始化所有函数的定义,同时定义所有函数的保留字。这里的所有函数包括BuildinFunTable、GlobalFunTable、RolapSchemaRolapFunctionTable。

  Mondrian中各种函数类的关系如图10所示:

图10

  生成函数表对象之后,再由xmlSchema对象包含的多维对象生成Mondrian最终使用的多维对象。这一过程通过初始化xml文件中定义的多维模型可能用到的参数,命名集,RolapCube类型的立方体和虚拟立方体来完成。

  RolapSchema对象维护了一个RolapStar(星型模式定义)池,当初始化一个立方体时,访问这个RolapStar池,参数是这个立方体对应的事实表名。

  如果存在对应的RolapStar对象,那么直接设置立方体的star,如果不存在,则生成一个新RolapStar对象再设置。当生成新的RolapStar对象时,就会调用RoalpSchema对象的interConnection成员的datasource,根据这个datasource去返回所连接的数据库的特征参数,为之后生成特定的sql语句做准备。

  在这里可以对RolapConnection、RolapSchema、RolapCube、RolapStar之间的关系做个小结:多个connection可能对应一个schema,每个schema又有一个internalConnection,并且可能有多个cube,多个cube可能对应一个star。Mondrian构造了很多对象池,这种做法提高了对内存有限空间的利用率。

  (4) 最后Load(String,String)方法调用aggTableManager.intialze()。聚集表管理器的初始化和星型模型有很大关系,同时它利用触发器机制对Mondrian.properties文件进行监听,Mondrian.properties中property值的改变能及时反映到聚集表管理器中,从而影响到聚集的动作。

  至此,一个schema的初始化过程全部完成,流程从Schema Manager重新转向Session Manager,Session Manager下一步将解析传入的MDX语句。从以上的分析可见,Session Manager是十分重要的一环,它与后面的Aggregate Manager、Dimensional Manager联系也十分紧密。初始化的工作为之后的多维分析操作奠定了牢固的基础。在Schema Manager部分,可以优化的地方不是很多,唯一可以能提高效率的地方便是xml文件的编写,设计高效的多维模式、灵活的运用Mondrian提供的配置参数有助于提高之后数据处理操作的效率

本文作者:
« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3