使用了很久的saiku,决定跟踪一下代码,看看它的执行核心过程:

一、入口controller代码

1.1、页面打开之后,会发送一个ajax请求
Request URL:
http://l-tdata2.tkt.cn6.qunar.com:8080/saiku/rest/saiku/api/query/execute
Request Method:
POST
1.2、controller,java文件org.saiku.web.rest.resources.Query2Resource
如果有缓存,直接输出数据
没有缓存,计算在输出数据

二、service代码

2.1、service,执行核心代码 org.saiku.service.olap.ThinQueryService的private CellDataSet execute(ThinQuery tq, ICellSetFormatter formatter)方法
执行mdx语句
            Long start = (new Date()).getTime();
log.debug("Query Start");
CellSet cellSet = executeInternalQuery(tq); //这是执行mdx语句的地方,需要较长时间
log.debug("Query End");
String runId = "RUN#:" + ID_GENERATOR.get();
Long exec = (new Date()).getTime();

三、核心代码

执行mdx语句 org.saiku.service.olap.ThinQueryService的CellSet executeInternalQuery(ThinQuery query) throws Exception 方法
    CellSet executeInternalQuery(ThinQuery query) throws Exception {
String runId = "RUN#:" + ID_GENERATOR.getAndIncrement();
QueryContext queryContext = context.get(query.getName()); if (queryContext == null) {
queryContext = new QueryContext(Type.OLAP, query);
this.context.put(query.getName(), queryContext);
} // 根据数据立方体建立olap的jdbc链接
OlapConnection con = olapDiscoverService.getNativeConnection(query.getCube().getConnection());
if (StringUtils.isNotBlank(query.getCube().getCatalog())) {
con.setCatalog(query.getCube().getCatalog());
} if (queryContext.contains(ObjectKey.STATEMENT)) {
Statement s = queryContext.getStatement();
s.cancel();
s.close();
s = null;
queryContext.remove(ObjectKey.STATEMENT);
} OlapStatement stmt = con.createStatement(); // 实例化Statement对象
queryContext.store(ObjectKey.STATEMENT, stmt); query = updateQuery(query); try {
String mdx = query.getParameterResolvedMdx();
log.info(runId + "\tType:" + query.getType() + ":\n" + mdx); CellSet cs = stmt.executeOlapQuery(mdx); //这里是执行mdx语句的过程,耗时最久
queryContext.store(ObjectKey.RESULT, cs);
//追踪代码cs使用
log.info("cs:" + cs.toString());
if (query != null) {
queryContext.store(ObjectKey.QUERY, query);
}
//追踪代码query使用
log.info("query:" + query.toString());
return cs;
} finally {
stmt.close();
queryContext.remove(ObjectKey.STATEMENT);
}
}

四、执行日志:

上面的注释,是通过日志来作证的,日志如下:

-- ::, DEBUG [org.saiku.web.rest.resources.Query2Resource] TRACK        /query/F7CE71C7-3E29-0A6A-9BC9-FDDA1A129BB7    POST     tq:false file:/homes/saiku_search.saiku
-- ::, DEBUG [org.saiku.service.olap.ThinQueryService] Query Start
2016-06-12 14:46:21,814 INFO [org.saiku.service.olap.ThinQueryService] RUN#: Type:QUERYMODEL:
WITH
SET [~COLUMNS] AS
{[category_name_id].[category_name_id].[category_name].Members}
SET [~ROWS_rpt_date_rpt_date] AS
{[rpt_date].[rpt_date].[--]}
SET [~ROWS_partner_partner] AS
Hierarchize({{[partner].[partner].[All partners]}, {[partner].[partner].[name].Members}})
SET [~ROWS_from_area_id_from_area_id] AS
Hierarchize({{[from_area_id].[from_area_id].[All from_area_ids]}, {[from_area_id].[from_area_id].[name].Members}})
SET [~ROWS_utmr_page_id_utmr_page_id] AS
{[utmr_page_id].[utmr_page_id].[All utmr_page_ids]}
SET [~ROWS_in_track_in_track] AS
{[in_track].[in_track].[All in_tracks]}
SET [~ROWS_dist_city_dist_city] AS
{[dist_city].[dist_city].[All dist_citys]}
SET [~ROWS_current_city_current_city] AS
{[current_city].[current_city].[All current_citys]}
SET [~ROWS_from_value_id_from_value_id] AS
{[from_value_id].[from_value_id].[All from_value_ids]}
SET [~ROWS_page_id_page_id] AS
{[page_id].[page_id].[All page_ids]}
SELECT
NON EMPTY CrossJoin([~COLUMNS], {[Measures].[num], [Measures].[gid]}) ON COLUMNS,
NON EMPTY NonEmptyCrossJoin([~ROWS_rpt_date_rpt_date], NonEmptyCrossJoin([~ROWS_partner_partner], NonEmptyCrossJoin([~ROWS_from_area_id_from_area_id], NonEmptyCrossJoin([~ROWS_utmr_page_id_utmr_page_id], NonEmptyCrossJoin([~ROWS_in_track_in_track], NonEmptyCrossJoin([~ROWS_dist_city_dist_city], NonEmptyCrossJoin([~ROWS_current_city_current_city], NonEmptyCrossJoin([~ROWS_from_value_id_from_value_id], [~ROWS_page_id_page_id])))))))) ON ROWS
FROM [saiku_search_detail_cube]
2016-06-12 14:50:58,344 INFO [org.saiku.service.olap.ThinQueryService] cs:mondrian.olap4j.FactoryJdbc41Impl$MondrianOlap4jCellSetJdbc41@2c72fc4f
-- ::, INFO [org.saiku.service.olap.ThinQueryService] query:org.saiku.olap.query2.ThinQuery@3112bd55
-- ::, DEBUG [org.saiku.service.olap.ThinQueryService] Query End
-- ::, DEBUG [org.saiku.service.olap.ThinQueryService] cellSet2Matrix End
-- ::, DEBUG [org.saiku.service.olap.ThinQueryService] calculateTotals End
-- ::, INFO [org.saiku.service.olap.ThinQueryService] RUN#: Size: / Execute: 276658ms Format: 98ms Totals: 1ms Total: 276757ms

上面是执行了一个超级数据的日志,红色部分标志出了执行时间最久的部分,日志是我重新编译代码得出的,可见执行的核心代码就是第三部分标出的红色部分代码

五、olap4j引擎

第四部分的代码,核心是建立olap的jdbc链接。下面是原文:http://www.olap4j.org/

olap4j is an open Java API for OLAP.
Think of it like JDBC, but for accessing multi-dimensional data. olap4j is a common API for any OLAP server, so you can write an analytic application on one server and easily switch it to another. Built on that API, there is a growing collection of tools and components.

这个略微有点抽象,走到这一步,说明大家已经明白了数据立方体的定义,以及上传的xml文件就定义了一个多维数据库(不明白的同学翻看以前的博客:http://www.cnblogs.com/liqiu)。那么定义好了多维数据库,就需要获取里面的数据,olap4j就是这样的一个实现了jdbc规范的多为数据库查询引擎!

总结:

看了上面的过程,大家就能了解saiku的执行过程了吧

  1. saiku前端发送mdx查询ajax请求
  2. saiku后端接收mdx语句
  3. 包装一下查询内容
  4. 调用olap4j引擎查询数据库结果
  5. 修饰数据并返回
  6. saiku前端展示出来

预告:下一期会讨论一下saiku的缓存机制

saiku执行过程代码跟踪的更多相关文章

  1. openstack学习笔记一 虚拟机启动过程代码跟踪

    openstack学习笔记一 虚拟机启动过程代码跟踪 本文主要通过对虚拟机创建过程的代码跟踪.观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程. 当从horizon界面发 ...

  2. ASP.NET Web API 过滤器创建、执行过程(二)

    ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...

  3. jdbc执行过程 jar包下载

    工具和准备: MYSQL 8.0jar包: 链接:https://pan.baidu.com/s/1O3xuB0o1DxmprLPLEQpZxQ 提取码:grni 使用eclipse开发首先把jar包 ...

  4. ASP.NET WEB API 中的路由调试与执行过程跟踪

    路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...

  5. javascript代码解释执行过程

    javascript是由浏览器解释执行的脚本语言,不同于java c,需要先编译后运行,javascript 由浏览器js解释器进行解释执行,总的过程分为两大块,预编译期和执行期 下面的几个demo解 ...

  6. java代码的编译、执行过程

    Java代码编译是由Java源码编译器来完成,流程图如下所示: Java字节码的执行是由JVM执行引擎来完成,流程图如下所示: Java代码编译和执行的整个过程包含了以下三个重要的机制: Java源码 ...

  7. JS-预解析(提升)与代码执行过程

    1,预解析的过程. 2,代码的执行过程. 预解析:程序在执行过程,会先将代码读取到内存中检查,会将所有的声明在此处进行标记,所谓的标记就是让js解析器知道这个名字,后面在使用这个名字的时候,不会出现未 ...

  8. CLRMonitor - 跟踪CLR内部执行过程工具

    CLRMonitor v1.0.1511.13 点击此处下载 软件介绍:这款软件主要用于跟踪CLR内部执行过程,定位当前程序执行的命名空间以及方法名等信息.可以迅速找到被跟踪程序的当前执行方法名.本软 ...

  9. Pythontutor:可视化代码在内存的执行过程

    http://www.pythontutor.com/visualize.html今天去问开发一个Python浅拷贝的问题,开发给了一个神器,可以可视化代码在内存的执行过程,一看即懂,太NB了!~真是 ...

随机推荐

  1. 用c#开发微信 (16) 微活动 2 刮刮卡

    微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式.这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公 ...

  2. js常规日期格式处理、月历渲染、倒计时函数

    日期格式处理在前端的日常任务中非常常见,但是为此引入monent.js这样的类库又会显得有点臃肿,毕竟我们一个特定的项目中,并不需要monent.js那么全的涵盖范围.另外,如果现在公司让你自己手写一 ...

  3. 旋转V字俄罗斯方块

    实现效果如图,也就是一个图像的旋转.注意,旋转后的文字是相对应的,而且文字还是立起的.第一次点击时显示,第二次点击时开始旋转.下面是我做这个效果的记录,方法这么差,我也就不说什么了. 先上HTML/C ...

  4. Atitit.信息论原理概论attilax总结

    Atitit.信息论原理概论attilax总结 1. <信息论基础(原书第2版)>((美)科弗(Cover...)[简介_书评_在线阅读] - 当当图书.html1 2. <信息论- ...

  5. atitit.dw不能显示正确的百分比高度in dw的解决

    atitit.dw不能显示正确的百分比高度in dw的解决 div 设置35%的高度,三,不能正确的显示高度...环境dw cs6 但是设置161px奏能ok了...表明这个是dw的一个bug... ...

  6. paip.取当天记录的方法sql跟hql hibernate

    paip.取当天记录的方法sql跟hql hibernate #------两个方法...函数法和日期计算法.. 函数法: DATEDIFF(d,createTime,GETDATE())=0   / ...

  7. JAVA编程中的类和对象

    1:初学JAVA,都知道JAVA是面向对象的编程.笔者这节开始说说类和对象.(实例仅供参考,如若复制粘贴记得修改包名和类名,避免出错) 学习JAVA的快捷键,Alt+/代码补全功能,其实此快捷键启动了 ...

  8. 虚拟机下samba简单安装配置

    系统是Win7 虚拟机是CenterOS6.5 1.关闭防火墙以及关闭SELINUX的强制模式(重要): service iptables stop//关闭防火墙 setenforce 0 //关闭S ...

  9. SQLite 批量insert - 如何加速SQLite的插入操作

    本人翻译, 原文见: http://tech.vg.no/2011/04/04/speeding-up-sqlite-insert-operations/ 我正在开发一个Android程序, 它使用S ...

  10. nginx 负载均衡集群解决方案 healthcheck_nginx_upstreams (一)

    该文章来源于互联网,目前找不到原作者,放在这里的目的是记录healthcheck_nginx_upstreams 的安装过程和相关配置,在起初安装成功后不能够正常运行healthcheck_nginx ...