mondrian源码分析与说明 联系客服

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

evaluateCurrent()方法。EvaluateCurrent内真正获取单元值的地方是调用:cellReader.get(this);此处使用的cellReader为

FastBatchingCellReader类,调用其get()方法,内部实际是从

aggregation的缓存中获取单元值。

? 最后所有的单元对象CellInfo存放在CellInfoContainer中,通过

cellkey进行索引。

? 问题是,上述最终是从aggregation缓存中获取单元值的,但一开始缓存

中的值又从哪里来呢,这是个关键问题。原来executeBody第一次调用ExecuteStripe()时,从缓存中获得的值都只是空值,但同时会记录下所有的cellRequest信息;然后执行完executeBody后紧接着就会调用FastBatchingCellReader的另一个方法loadAggregation,该方法内部会根据刚才设定的cellRequest信息实际从数据库中读取信息并赋予这些cells。再之后会第二次执行ExecuteStripe从而获取到真正的cell值,循环往复,直至没有新的cellRequest产生为止。参见executeBody主体代码: While(true){ }

evaluator.setCellReader(fastBatchingCellReader); ExecuteStripe(evaluator);

If(!fastBatchingCellReader.loadAggregation(query))

return;//此处可以退出循环了。

? 其实上面的第一步骤或第二步骤中,在决定各轴成员值时,可能就需要获

取cell值(如排序函数),此时就已经会记录request和进行loadAggregation了;如果这样的话,到第三步时可能缓存中就已经有值可以直接获取了。

? 研发注意:在RolapEvaluator中,许多方法对性能的影响很大,这里都用

了final,以便JVM可以优化它们。如果未来需要的话,final可以移除,方法可以重写。

2.5 执行完execute后,将mondrian的result转换成JPivot的result。

4. 修改点

4.1. mondrian角色参数化

mondrian本身是支持角色的(但mondrian本身不负责角色与用户的挂钩);在实际应用中,角色往往不能事先定义死,而是可能定义出一个角色模版,但里面会有些参数;实际运行时再把这些参数实例化。例如:

在mondrian的ROlapSchema模型对象中原有一个mapNameToRoles哈希表,存储着schema中所有的role对象(不是role定义,role定义本身是另外一个对象);在mondrian的ROlapConnection对象中则有一个role对象,代表当前connection使用的角色;该角色实际上是引用schema角色组中的某个角色,schema角色组中的对象为所有连接共享。

当引入参数化需求后,由于每个连接建立时传递的参数都不一样,因此原schema中的角色对象组列表已经没有意义,原schema中的role定义信息则还需要保留下来;而connection中的role对象则每次都根据实例参数重新创建。

相应的修改之处为(查找 add by zyz之处即可):

? mondrian.rolap.RolapSchema类中,修改了createRole方法,并相应的添加了几

个辅助方法。

? mondrian.rolap.RolapConnection类中,相应的把role的获取方法做了些修改。 ? jpivot

中,com.tonbeller.jpivot.tags.MondrianModelFactory

添加

grantParameters属性。

? jpivot中,..MondrianOlapModelTag类中同理添加grantParameters属性,并且

增加:cfg.setGrantParameters(grantParameters)。 ? 相应的需要修改jpiovt-tags.tld,增加grantParameters属性。

4.2. 缓存失效控制

建议在jpivot.mondrian.mondrianModel类的destroy()方法中加入下面代码: mondrian.rolap.RolapSchema rschema =

(mondrian.rolap.RolapSchema)monConnection.getSchema();

rschema.flushRolapStarCaches(true); 以实现在一次新的连接建立后,清理缓存。但由于缓存是全局共享的,故要注意同步问题。Mondrian已经很好地处理了同步的问题。譬如在上述destroy中会把aggregations清空,但这便不意味着其中的单个aggregation已经销毁,相反可能正在另外一个连接中被使用;但在该连接的下一个循环中就会发现aggregations已经空了,所有的aggregation又将按需重建。由于mondrian内部的求cell过程是个无限循环过程,直至发现没有什么聚合再需要求取时才退出,因此不用担心aggreations被一个连接清空了,而另外一个连接读取不到数据。

RolapConnection类,通过新增加的DriverManagerDataSourceReg类来获得

DriverManagerDataSource。

RolapSchema 的md5算法增加了连接字符串。

4.3. connection创建参数优化

? 优化,数据库连接,直接传递DataSource

? 优化catalog,直接传递schema字符串或字符流,减少磁盘I/O操作。

? 优化 schema 创建, 传递知识库缓存key,创建schema的时候通过缓存代理读取

MondrianDef.Schema

4.4. 维度成员排序

Mondiran已经很好地实现了基于单元值的排序,但有的场合下还需要有基于维度成员的排序。为此需要在olap schema文件的level中设置如下(见其中的ascending属性):

name=\

column=\

type=\

uniqueMembers=\

ascending=\年\。其中,若ascending为false为降序,否则为升序,缺省若不设置ascending则为true。

当然,基于单元值的排序其优先级大于基于维度成员的排序。 相应的修改之处有:

? Mondrian.olap.MondrianDef类中的Level子类,添加了ascending及其相关读取和

展现代码片段。

? mondrian.rolap.RolapLevel中也添加了ascending属性。

? mondrian.rolap.RolapMember中对compareTo()方法进行了修改,加入了对ascending

的判断。(此处是为了在cell排序过程中,当cell相当时再按成员值排序,那么此时就会用到member的compareTo()了)。

? mondrian.rolap.RolapStar类中的Column子类中添加了ascending及其相关读取和展

现代码片段;其中Table子类中的makeColumnForLevelExpr()中的column创建处作了相应修改。(此处没有用到)

? mondrian.rolap.SqlMemberSource类中的sqlQuery.addOrdBy()方法中的第二个参数

全部替换成level.isAscending()。--关键的,在一开始缓存成员值时就会用到。 ? mondrian.rolap.SqlTupleReader类中的sqlQuery.addOrdBy()方法中的第二个参数全

部替换成level.isAscending()。--关键的,在一开始缓存成员值时就会用到。

4.5. 对mondrian bug的修正

1、 父子维度无法展开的问题:

修改mondrian.rolap.SqlMemberSource.getMemberChildren()函数。

从jpivot.mondrian.MondrianQueryAdapter.canExpand()中作为入口进入。 2、 维度成员在crossjoin时的乱序问题

修改了内部类PositionIter,使其每次都返回新的iterator。

3、mondrian.rolap.RolapMember.getName()修改了,以支持level的列名是整形。

4.6. to-do List

1、请求解决方案里的一个cube,若其他cube涉及到的表没有,则当前cube也会失败。