mondrian源码分析与说明

发布时间 : 星期一 文章mondrian源码分析与说明更新完毕开始阅读

Predicates: Year=1997, Quarter=any, Nation=USA, State={OR, WA}

2.6.4. 缓存失效控制

为了提高访问效率,必须要使用缓存;但使用缓存必须在数据库底层数据发生变化时做好数据的失效和刷新工资。

老版的做法非常粗略:mondrian.rolap.RolapSchema.clearCache();这意味着连mondrian schema都被失效,与之关联的全部缓存也都被失效。

新版的做法是引入了mondrian.olap.CacheControl接口,可以很精细地由应用控制缓存。为此mondrian引入了cell region的概念,region是由一个或多个成员定义出的多维空间(定义时可以指定是否包含这些成员的子成员)。为了使缓存失效,你需要首先定义一个region,然后告诉mondrian失效该region内的所有cells;为了确保一致性,mondrian还会自动地把这些cell的聚合单元也一起失效。具体参见

CacheControl.CellRegion类。最终调用cacheControl.flush(cellRegion)。

具体失效时,还是针对segment进行的,因为mondiran中的cell缓存是通过segment组织的。失效发生时,可能segment中的部分cell无用了,但mondrian并不会真正删除这些cell,而是strengthened其predicates,例如失效前的某个segment为:

1997 USA OR xxx 1997 USA WA xxx

Predicates: Year=1997, Nation=USA, State={OR, WA}

然后Crossjoin([time].[1997].[Q2],[Customer].[USA].[OR])的cellRegion失效,此时该segment变为:

1997 USA OR xxx 1997 USA WA xxx

Predicates: Year=1997, Nation=USA, State={WA}

目前这样处置未必最合理,因为会有内存泄露。将来可能根据该segment中的cell达到一定的失效阀值,就彻底把该segment抛弃掉。

Segment的合并也是将来应考虑的事情,以减少segment碎片。 维度成员值的缓存控制目前mondrian还未提供控制接口。

但是metaCacheControl,例如控制schema xml等还是提供不少接口了,例如: ? mondrian.rolap.RolapSchema.clearCache() ? mondrian.olap.MondrianServer.flushSchemaCache()

? mondrian.rolap.cache.CachePool.flush()

? mondrian.rolap.RolapSchema.flushRolapStarCaches(boolean) 该方法不失效

schema,但失效缓存,在应用层还不想使用cellRegion失效缓存前,可以适度使用。

? mondrian.rolap.RolapSchema.flushAllRolapStarCachedAggregations() ? mondrian.rolap.RolapSchema.flushSchema(String,String,String,String) ? mondrian.rolap.RolapSchema.flushSchema(DataSource,String)

3. 交互管理层

MondrianModel 是JPivot中用来展现一个MDX查询的所有原数据的模型。这里主要讲MondrianModel的三个方法,initialize(),getResult(),destroy()。

3.1. 初始化MondrianModel

1、 在

jpivot.mondrian.MondrianModel

执行

initialize()方法之前,先用

MondrianModelFactory.Config对象为MondrianModel对象设置jdbc,schema url等参数。 2、 调用

mondrian.olap.DriveManager.getConnection()方法,创建并返回

mondrian.rolap.RolapConnection对象,置于变量monConnection中;创建连接的参数指定详见mondrian.olap.RolapConnectionProperties。

2.1 在创建RolapConnection对象的构造函数中,会用对象池技术建立mondrian.rolap.RolapSchema对象。该对象会被缓存在对象池中,只会创建一次(RolapSchema对象中还有一个大对象xmlSchema,是纯定义性质的,Mondrian.olap.MondrianDef.Schema);这里需要注意的是:

? RolapSchema对象的建立有几种方法:首先schema字符串内容本身可以通过参数

直接传递进来;也可以通过url地址指定;还可以通过自定义的DynamicSchemaProcessor类来给定(这样就有机会动态对schena内容进行修改)。 ? RolapSchema对象本身的建立一般是从缓存中读取,没有时则创建。但若使用了上

述的DynmicSchemaProcessor则每次都会重新创建;并且若指定了UseContentChecksum参数 (将使用md5对字符串内容编码),若UseContentChecksum为true,则 md5编码值与以前的不同,则即使存在了RolapSchema对象也会重新创建。可与DynamicSchemaProcessor属性一起用。

? 在Mondrian新版本3.0中,RolapConnectionProperties 中除了定义了

DynamicSchemaProcessor 和UseContentChecksum 参数,还新增了UseSchemaPool属性,如果该属性为false,将禁用schema缓存。 2.2 最后调用RolapSchema.createRole()方法创建该连接关联的role对象(如果指定了的话);并创建ROlapSchemaReader对象(和role绑定的,读取时会进行必要的控制)。

2.3 根据传入的参数设置locale,没有的话按照en处理。

3、调用connection的parseMDX(),最终调用ConnectionBase.parseQuery()方法准备好一个mondrian.olap.Query对象,置入成员变量monQuery;query对象由mondrian.olap.parse对象生成,该对象是一个自动生成的类,使用了javacup技术。

3.2. 获取结果集

1、 之前确保MondiranModel中的monQuery对象已经创建好。

2、 Jpivot中,界面会调用jpivot.table.TableCompont对象的render方法进行绘制,最终

会调用MondrianModel.getResult()的方法,但返回的是jpivot.olap.model.Result对象,并非mondrian.olap.Result对象。

2.1 首先执行MondrianQueryAdapter对象queryAdapter的onExecute()。得到mdx

语句。

2.2 调用monConnection.execute(monQuery)获取mondrian result对象;内部会创建

new ROlapResult(monQuery,true),RolapResult得到的是运行中请求的结果,其中ture代表要实际装载数据。 2.3 内部会进行Evaluator算法:

显式成员:在轴上的成员。

隐式成员:不在轴上的成员,可能是在函数中。

如果一个维度的成员都是隐式成员,相当于在切片上使用默认成员。

有两种特定维度:时间维度和度量维度。 时间维度

度量维度的默认成员是没有所有的××的,约定成俗的是第一个度量。

首先,RolapEvaluator会被创建。创建过程中,它会从每个hierarchy中获取一

个member,每个member是hierarchy的默认成员。对于大多数hierarchy,这个默认成员就是所有成员。可能有两种例外:1)hierarchy没有所有成员;2)hierarchy有所有成员但是它不是默认成员。这样的话,默认成员仍然会被使用,但是可能会有问题。

然后载入所有无所有成员的hierarchy的根成员,载入非默认成员的所有的成员。

2.4 内部会进行Evaluator算法,三大步骤:

? Determine axes步骤:决定每个轴上的所有成员,但此时还不保存信息(不

创建RolapAxis)。

确定切片轴上的成员。轴上发现的成员都会被加入到AxisMember中。如果该成员是度量,则切片指明请求的度量,并将该度量放入evaluator的context中(取代cube中的第一个度量,即默认度量)。其它的切片成员也会被放入evaluator的context的。

? execute axes步骤:为每个轴保存所有成员,创建RolapAxis对象(重复了第

一步骤,只是此时创建了RolapAxis对象,该对象是结果集中的维度成员值部分)。执行第一步和第二步时确保数据已经载入。

? get cell步骤:根据轴上的成员值计算并存储每个单元值(结果集的cell值部

分),参见executeBody()方法,内部主要调用executeStripe()方法, ? ExecuteStripe()方法内部采用递归方法依次获取每个单元值,从行轴

开始(轴位置索引最大的那个),针对每个行轴的mondrian.olap.position进行循环,在一个循环内再针对列轴的每个position进行循环,求得交叉点的cell值。每个position由一个或多个维度成员值组成,具体的个数同该轴上交叉的维度数;在计算某cell值之前,会依次用该cell的member值(包括切片上的维度值)设

evaluator

context

evaluator.evaluateCurrent()方法获得当前context下的cell值。

? Evaluator.evaluateCurrent()内部可能会执行到间接递归调用,

这个发生在执行计算成员值的情况下;此时为了计算成员,首先需要获取其他度量值,而为了获取这些前置的度量值又要调用

联系合同范文客服:xxxxx#qq.com(#替换为@)