跨庫多維分析後臺的實現
問題的提出
多維分析(BI)系統後臺資料常常可能來自多個數據庫,這時就會出現跨庫取數計算的問題。
例如:從效能和成本考慮,往往會限制生產庫的容量,同時將歷史資料分庫存放,由ETL定期把生產庫中新產生的資料同步到歷史庫中,同步週期根據資料的生成量,可能是1天、一週或者一個月。如果多維分析系統僅僅連上歷史庫取數,那麼使用者就只能對歷史資料做分析,也就是實現T+1、T+7、T+30的多維分析。如果想要實現T+0的實時分析,就要從生產庫和歷史庫分別取得資料進行計算並最終合併結果。很多時候,生產庫和歷史庫還是異構的資料庫,很難直接做跨庫混合運算。
即使不是T+0場景,歷史資料量很大時也可能分成多個數據庫儲存,而且也會是是異構資料庫的情況。這時,多維分析系統也需要從多個不同資料倉庫中取數、計算、合併結果展現。
解決思路與過程
作為資料計算中介軟體(DCM),構建資料前置層是集算器的重要應用模式。集算器具備可程式設計閘道器機制,可以同時連上多個數據庫取數,並將結果合併提交給前臺展現。
案例場景說明
在下面的案例中,多維分析系統要針對訂單資料做自助分析。為了簡化起見,我們採用了以下模擬環境:
l 多維分析系統前臺用tomcat伺服器中的jdbc.jsp進行模擬。Tomcat安裝在windows作業系統的C:\tomcat6。
l 集算器JDBC整合在多維分析應用中。jdbc.jsp模仿多維分析應用系統,產生符合集算器規範的SQL,通過集算器JDBC提交給集算器SPL指令碼處理。
l 多維分析系統的資料一部分來自於生產資料庫(Oracle資料庫) demo中的ORDERS表,另一部分來自歷史庫(Mysql資料庫)test。當天資料連線生產庫取數,實現實時分析。
l ETL過程每天將當天的最新資料同步到歷史庫中。日期以訂購日期ORDERDATE為準,假設當前的日期是2015-07-18。ORDERDATE的開始和結束日期是多方位分析的必選條件。
案例中包含生產庫和1個歷史庫,實際上集算器也支援一個生產庫和同時多個歷史庫,或者沒有生產庫但有多個歷史庫的情況。
後臺資料初始化準備
用下面的sql檔案在ORACLE資料庫中完成ORDERS表的建表和資料初始化。
資料截止到2017年7月18日。
用下面的sql檔案在MYSQL資料庫中完成ORDERS表的建表和資料初始化。
資料截止到2017年7月17日。
集算器實現跨庫查詢
1、 將下面壓縮檔案中的 CrossDB 目錄複製到 tomcat 的應用目錄。
目錄結構如下圖:
配置檔案在 classes 中,在官網上獲取的授權檔案也要放在 classes 目錄中。集算器的 Jar 包要放在 lib 目錄中(需要哪些 jar 請參照集算器教程)。
修改 raqsoftConfig.xml 中的主目錄配置:
<mainPath>C:\tomcat6\webapps\CrossDB\WEB-INF\dfx</mainPath>
<JDBC>
<load>Runtime,Server</load>
<gateway> CrossDB.dfx</gateway>
</JDBC>
2、 編輯 CrossDB 目錄中的 jdbc.jsp,模擬前臺介面提交 sql 展現結果。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page import="java.sql.*" %>
<body>
<%
String driver = "com.esproc.jdbc.InternalDriver";
String url = "jdbc:esproc:local://";
try {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url);
Statement statement = conn.createStatement();
String sql =" select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE between date('2011-07-18') and date('2015-07-18') and AMOUNT>100 ";
out.println("Test page v1<br><br><br><pre>");
out.println("訂單 ID"+"\t"+" 客戶 ID"+"\t"+" 僱員 ID"+"\t"+" 訂購日期 "+"\t"+" 訂單金額 "+"<br>");
ResultSet rs = statement.executeQuery(sql);
int f1,f6;
String f2,f3,f4;
float f5;
while (rs.next()) {
f1 = rs.getInt("ORDERID");
f2 = rs.getString("CUSTOMERID");
f3 = rs.getString("EMPLOYEEID");
f4 = rs.getString("ORDERDATE");
f5 = rs.getFloat("AMOUNT");
out.println(f1+"\t"+f2+"\t"+f3+"\t"+f4+"\t"+f5+"\t"+"<br>");
}
out.println("</pre>");
rs.close();
conn.close();
} catch (ClassNotFoundException e) {
System.out.println("Sorry,can`t find the Driver!");
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
%>
</body>
在 jsp 中,先連線集算器的 JDBC,然後提交執行 SQL。步驟和一般的資料庫完全一樣,具有很高的相容性和通用性。對於多維分析工具來說,雖然是介面操作來連線 JDBC 和提交 SQL,但是基本原理和 jsp 完全一樣。
3、 開啟 dfx 目錄中的 CrossDB.dfx,觀察理解 SPL 程式碼。
傳入引數是 sql 例如:
select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE between date('2011-07-18') and date('2015-07-18') and AMOUNT>100。
SPL指令碼如下:
A |
B |
C |
|
1 |
=A1.pselect("ORDERDATE between*") |
||
2 |
=substr(A1(B1),"date(") |
=substr(A1(B1+1),"date(") |
|
3 |
=mid(A2,2,10) |
=mid(B2,2,10) |
|
4 |
if between(date(now()),date(A3):date(B3)) |
||
5 |
=connect("orcl") |
[email protected]("select ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from orders where orderdate=?",date(now())) |
|
6 |
=connect("mysql") |
[email protected]("select ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from orders") |
|
7 |
=mcs=[C5,C6].mcursor() |
=connect()[email protected]("with orders as(mcs)"+sql) |
|
8 |
return C7 |
||
9 |
else |
=connect("mysql") |
[email protected](sql.sqltranslate("MYSQL")) |
10 |
return C9 |
說明:
A1:解析 SQL,獲取 where 子句,並用空格來拆分成序列。
B1,A2-B3:在 A1 序列找到必選條件訂購日期,獲取開始和結束日期值。
A4:判斷查詢範圍是否包含當前日期。
B5-C6:如果包含當前日期,就連線生產庫和歷史庫,建立取數遊標。
B7:用生產庫和歷史庫遊標建立多路遊標。
C7、B8:對多路遊標進行 sql 查詢並返回結果。
A9-C10:如果不包含當前日期,就只連線歷史資料庫。將 SQL 翻譯成符合 MYSQL 資料庫規範的 SQL, 執行 SQL 得到遊標並返回。
實際業務中,生產庫一般都有必要保持一些歷史資料,這樣生產庫和歷史庫會有重複資料,所以程式碼中需要給生產庫再加上日期條件。如果是多個歷史庫分庫的情況,一般來講,這些庫之間就沒有重複的資料,程式碼能夠簡化一些。比如,假設例中的 ORACLE 和 MYSQL 沒有重複資料,則 CrossDB.dfx 的程式碼可以簡化如下:
A |
B |
|
1 |
=connect("orcl") |
[email protected]("select ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from orders") |
2 |
=connect("mysql") |
[email protected]("select ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from orders") |
3 |
=mcs=[B1,B2].mcursor() |
=connect()[email protected]("with orders as(mcs)"+sql) |
4 |
return B3 |
4、 啟動 tomcat,在瀏覽器中訪問http://localhost:8080/CrossDB/jdbc.jsp,檢視結果。
結果中訂購日期格式略有不同,這隻需要在多維分析前端設定一下顯示格式即可。
我們還可以繼續測試如下情況:
1、 僅僅查詢歷史庫
sql ="select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE between date('2011-07-18') and date('2015-07-18') and AMOUNT>100";
2、 分組查詢
sql ="select CUSTOMERID,EMPLOYEEID,sum(AMOUNT) S,count(1) C from ORDERS where ORDERDATE between date('2011-07-18') and date('2015-07-18') group by CUSTOMERID,EMPLOYEEID"
ETL過程
在這個案例中,集算器SPL指令碼還可以承擔ETL的工作。
多維分析系統上線之後,要每天晚上定時同步當天最新的資料。我們假設當天日期是2015-07-18。
SPL語言指令碼etl.dfx將當天資料增量補充到歷史庫中,具體指令碼如下:
A |
|
1 |
=connect("orcl") |
2 |
[email protected]("select ORDERDATE,CUSTOMERID,EMPLOYEEID,ORDERID,AMOUNT from ORDERS where ORDERDATE=?",etlDate) |
3 |
=connect("mysql") |
4 |
[email protected](B2, ORDERS,ORDERDATE,CUSTOMERID,EMPLOYEEID,ORDERID,AMOUNT) |
5 |
>A3.close() |
etl.dfx的輸入引數是etlDate,也就是需要新增的當天日期。
etl.dfx指令碼可以用windows或者linux命令列的方式執行,結合定時任務,可以定時執行。也可以用ETL工具來定時呼叫。
windows命令列的呼叫方式是:
C:\Program Files\raqsoft\esProc\bin>esprocx.exe C: \etl.dfx 2015-07-18
linux命令是:
/raqsoft/esProc/bin/esprocx.sh /esproc/ etl.dfx 2015-07-18
應用推廣
作為資料計算中介軟體(DCM),由集算器提供的後臺資料來源可以支援各種前端應用,不僅限於前端是多維分析的情況,還可以包括例如大屏展示、管理駕駛艙、實時報表、大資料量清單報表、報表批量訂閱等等場景。
另外,集算器形成的後臺資料來源也可以將資料快取計算。這時,採用集算器實現的資料計算閘道器和路由,就可以在集算器快取資料和資料倉庫之間智慧切換,從而解決資料倉庫無法滿足的效能要求問題,例如常見的冷熱資料分開計算的場景。(具體做法參見《集算器實現計算路由優化BI後臺效能》)。
在另一些應用中,集算器也可以完全脫離資料庫,起到輕量級多維分析後臺的作用,這時的集算器就相當於獨立的中小型資料倉庫或者資料集市了。(具體做法參見《集算器實現輕量級多維分析後臺》。)