輕量級內存計算引擎

內存計算指數據事先存儲于內存,各步驟中間結果不落硬盤的計算方式,適合性能要求較高沧奴,并發(fā)較大的情況。

HANA长窄、TimesTen等內存數據庫可實現(xiàn)內存計算滔吠,但這類產品價格昂貴結構復雜實施困難纲菌,總體擁有成本較高。本文介紹的集算器同樣可實現(xiàn)內存計算疮绷,而且結構簡單實施方便翰舌,是一種輕量級內存計算引擎。

下面就來介紹一下集算器實現(xiàn)內存計算的一般過程冬骚。

一椅贱、 啟動服務器

集算器有兩種部署方式:獨立部署、內嵌部署只冻,區(qū)別首先在于啟動方式有所不同庇麦。

l 獨立部署

作為獨立服務部署時,集算器與應用系統(tǒng)分別使用不同的JVM喜德,兩者可以部署在同一臺機器上山橄,也可分別部署。應用系統(tǒng)通常使用集算器驅動(ODBC或JDBC)訪問集算服務舍悯,也可通過HTTP訪問驾胆。

n Windows下啟動獨立服務,執(zhí)行“安裝目錄esProcbinesprocs.exe”贱呐,然后點擊“啟動”按鈕丧诺。

n Linux下應執(zhí)行“安裝目錄/esProc/bin/ServerConsole.sh”。

啟動服務器及配置參數的細節(jié)奄薇,請參考: http://doc.raqsoft.com.cn/esproc/tutorial/fuwuqi.html 驳阎。

l 內嵌部署

作為內嵌服務部署時,集算器只能與JAVA應用系統(tǒng)集成馁蒂,兩者共享JVM呵晚。應用系統(tǒng)通過JDBC訪問內嵌的集算服務,無需特意啟動沫屡。

詳情參考 http://doc.raqsoft.com.cn/esproc/tutorial/bjavady.html 饵隙。

二、 加載數據

加載數據是指通過集算器腳本沮脖,將數據庫金矛、日志、WebService等外部數據讀入內存的過程勺届。

比如Oracle中訂單表如下:

訂單明細如下:

將上述兩張表加載到內存驶俊,可以使用下面的集算器腳本(initData.dfx):

A1:連接Oracle數據庫。

A2-A3:執(zhí)行SQL查詢免姿,分別取出訂單表和訂單明細表饼酿。query@x表示執(zhí)行SQL后關閉連接。函數keys可建立主鍵,如果數據庫已定義主鍵故俐,則無需使用該函數想鹰。

A4-A5:將兩張表常駐內存,分別命名為訂單和訂單明細药版,以便將來在業(yè)務計算時引用辑舷。函數env的作用是設置/釋放全局共享變量,以便在同一個JVM下被其他算法引用刚陡,這里將內存表設為全局變量,也就是將全表數據保存在內存中株汉,供其他算法使用筐乳,也就實現(xiàn)了內存計算。事實上乔妈,對于外存表蝙云、文件句柄等資源也可以用這個辦法設為全局變量,使變量駐留在內存中路召。

腳本需要執(zhí)行才能生效勃刨。

對于內嵌部署的集算服務,通常在應用系統(tǒng)啟動時執(zhí)行腳本股淡。如果應用系統(tǒng)是JAVA程序身隐,可以在程序中通過JDBC執(zhí)行initData.dfx,關鍵代碼如下:

1. com.esproc.jdbc.InternalConnection con=null;

2. try {

3. Class.forName("com.esproc.jdbc.InternalDriver");

4. con =(com.esproc.jdbc.InternalConnection)DriverManager.getConnection("jdbc:esproc:local://");

5. ResultSet rs = con.executeQuery("call initData()");

6. } catch (SQLException e){

7. out.println(e);

8. }finally{

9. if (con!=null) con.close();

10. }

這篇文章詳細介紹了JAVA調用集算器的過程 http://doc.raqsoft.com.cn/esproc/tutorial/bjavady.html

如果應用系統(tǒng)是JAVA WebServer唯灵,那么需要編寫一個Servlet贾铝,在Servlet的init方法中通過JDBC執(zhí)行initData.dfx,同時將該servlet設置為啟動類埠帕,并在web.xml里進行如下配置:

myServlet

com.myCom.myProject.myServlet

3

對于獨立部署的集算服務器垢揩,JAVA應用系統(tǒng)同樣要用JDBC接口執(zhí)行集算器腳本,用法與內嵌服務類似敛瓷。區(qū)別在于腳本存放于遠端叁巨,所以需要像下面這樣指定服務器地址和端口:

st = con.createStatement();

st.executeQuery("=callx(“initData.dfx”;[“127.0.0.1:8281”])");

如果應用系統(tǒng)非JAVA架構,則應當使用ODBC執(zhí)行集算器腳本呐籽,詳見 http://doc.raqsoft.com.cn/esproc/tutorial/odbcbushu.html

對于獨立部署的服務器锋勺,也可以脫離應用程序,在命令行手工執(zhí)行initData.dfx狡蝶。這種情況下需要再寫一個腳本(如runOnServer.dfx):

然后在命令行用esprocx.exe調用runOnServer.dfx:

D:raqsoft64esProcbin>esprocx runOnServer.dfx

Linux下用法類似宙刘,參考 http://doc.raqsoft.com.cn/esproc/tutorial/minglinghang.html

三、 執(zhí)行運算獲得結果

數據加載到內存之后牢酵,就可以編寫各種算法進行訪問悬包,執(zhí)行計算并獲得結果,下面舉例說明:以客戶ID為參數馍乙,統(tǒng)計該客戶每年每月的訂單數量布近。

該算法對應的Oracle中的SQL語句如下:

select to_char(訂單日期,'yyyy') AS 年份,to_char(訂單日期,'MM') AS 月份, count(1) AS 訂單數量 from 訂單 where客戶ID=? group by to_char(訂單日期,'yyyy'),to_char(訂單日期,'MM')

在集算器中垫释,應當編寫如下業(yè)務算法(algorithm_1.dfx)

為方便調試和維護,也可以分步驟編寫:

A1:按客戶ID過濾數據撑瞧。其中棵譬,“訂單”就是加載數據時定義的全局變量,pCustID是外部參數预伺,用于指定需要統(tǒng)計的客戶ID订咸,函數select執(zhí)行查詢。@m表示并行計算酬诀,可顯著提高性能脏嚷。

A2:執(zhí)行分組匯總,輸出計算結果瞒御。集算器默認返回有表達式的最后一個單元格父叙,也就是A2。如果要返回指定單元的值肴裙,可以用return語句

當pCustID=”VINET”時趾唱,計算結果如下:

需要注意的是,假如多個業(yè)務計算都要對客戶ID進行查詢蜻懦,那不妨在加載數據時把訂單按客戶ID排序甜癞,這樣后續(xù)業(yè)務算法中就可以使用二分法進行快速查詢,也就是使用select@b函數宛乃。具體實現(xiàn)上带欢,initData.dfx中SQL應當改成:

=A1.query("select 訂單ID,客戶ID,訂單日期,運貨費 from 訂單 order by 客戶ID")

相應的,algorithm_1.dfx中的查詢應當改成:

=訂單.select@b(客戶ID==pCustID)

執(zhí)行腳本獲得結果的方法烤惊,前面已經提過乔煞,下面重點說說報表,這類最常用的應用程序柒室。

由于報表工具都有可視化設計界面渡贾,所以無需用JAVA代碼調用集算器,只需將數據源配置為指向集算服務雄右,在報表工具中以存儲過程的形式調用集算器腳本空骚。

對于內嵌部署的集算服務器,調用語句如下:

call algorithm_1(”VINET”)

由于本例中算法非常簡單擂仍,所以事實上可以不用編寫獨立的dfx腳本囤屹,而是在報表中直接以SQL方式書寫表達式:

=訂單.select@m(客戶ID==”VINET”).groups(year(訂單日期):年份, month(訂單日期):月份;count(1):訂單數量)

對于獨立部署的集算服務器,遠程調用語句如下:

=callx(“algorithm_1.dfx”,”VINET”;[“127.0.0.1:8281”])

有時逢渔,需要在內存進行的業(yè)務算法較少肋坚,而web.xml不方便添加啟動類,這時可以在業(yè)務算法中調用初始化腳本,達到自動初始化的效果智厌,同時也省去編寫servlet的過程诲泌。具體腳本如下:

A1-B1:判斷是否存在全局變量“訂單明細”,如果不存在铣鹏,則執(zhí)行初始化數據腳本initData.dfx敷扫。

A2-A3:繼續(xù)執(zhí)行原算法。

四诚卸、 引用思維

前面例子用到了select函數葵第,這個函數的作用與SQL的where語句類似,都可進行條件查詢合溺,但兩者的底層原理大不相同卒密。where語句每次都會復制一遍數據,生成新的結果集辫愉;而select函數只是引用原來的記錄指針栅受,并不會復制數據将硝。以按客戶查詢訂單為例恭朗,引用和復制的區(qū)別如下圖所示:

可以看到,集算器由于采用了引用機制依疼,所以計算結果占用空間更小痰腮,計算性能更高(分配內存更快)。此外律罢,對于上述計算結果還可再次進行查詢膀值,集算器中新結果集同樣引用最初的記錄,而SQL就要復制出很多新記錄误辑。

除了查詢之外沧踏,還有很多集算器算法都采用了引用思維,比如排序巾钉、集合交并補翘狱、關聯(lián)、歸并砰苍。

五潦匈、 常用計算

回顧前面案例,可以看到集算器語句和SQL語句存在如下的對應關系:

事實上赚导,集算器支持完善的結構化數據算法茬缩,比如:

l GROUP BY…HAVING

l ORDER BY…ASC/DESC

l DISTINCT

l UNION/UNION ALL/INTERSECT/MINUS

與SQL的交并補不同,集算器只是組合記錄指針吼旧,并不會復制記錄凰锡。

l SELECT … FROM (SELECT …)

l SELECT (SELECT … FROM) FROM

l CURSOR/FETCH

游標有兩種用法,其一是外部JAVA程序調用集算器,集算器返回游標寡夹,比如下面腳本:

JAVA獲得游標后可繼續(xù)處理处面,與JDBC訪問游標的方法相同。

其二菩掏,在集算器內部使用游標魂角,遍歷并完成計算。比如下面腳本:

集算器適合解決復雜業(yè)務邏輯的計算智绸,但考慮到簡單算法占大多數野揪,而很多程序員習慣使用SQL語句,所以集算器也支持所謂“簡單SQL”的語法瞧栗。比如algorithm_1.dfx也可寫作:

上述腳本通用于任意SQL斯稳,

表 示 執(zhí) 行 默 認 數 據 源 ( 集 算 器 ) 的

語 句 , 如 果 指 定 數 據 源 名 稱 比 如

()表示執(zhí)行默認數據源(集算器)的SQL語句迹恐,如果指定數據源名稱比如 (orcl)挣惰,則可以執(zhí)行相應數據庫(數據源名稱是orcl的Oracle數據庫)的SQL語句。

from {}語句可從任意集算器表達式取數殴边,比如:from {訂單.groups(year(訂單日期):年份;count(1):訂單數量)}

from 也可從文件或excel取數憎茂,比如:from d:/emp.xlsx

簡單SQL同樣支持join…on…語句,但由于SQL語句(指任意RDB)在關聯(lián)算法上性能較差锤岸,因此不建議輕易使用竖幔。對于關聯(lián)運算,集算器有專門的高性能實現(xiàn)方法是偷,后續(xù)章節(jié)會有介紹拳氢。

簡單SQL的詳情可以參考: http://doc.raqsoft.com.cn/esproc/func/dbquerysql.html#db_sql_

六、 有序引用

SQL基于無序集合做運算蛋铆,不能直接用序號取數馋评,只能臨時生成序號,效率低且用法繁瑣刺啦。集算器與SQL體系不同留特,能夠基于有序集合運算,可以直接用序號取數洪燥。例如:

函數m()可按指定序號獲取成員磕秤,參數為負表示倒序。參數也可以是集合捧韵,比如m([3,4,5])市咆。而利用函數to()可按起止序號生成集合,to(3,5)=[3,4,5]再来。

前面例子提到過二分法查詢select@b蒙兰,其實已經利用了集算器有序訪問的特點磷瘤。

有時候我們想取前 N名,常規(guī)的思路就是先排序搜变,再按位置取前N個成員采缚,集算器腳本如下:

=訂單.sort(訂單日期).m(to(100))

對應SQL寫法如下:

select top(100) * from 訂單 order by 訂單日期 --MSSQL

select from (select from 訂單 order by 訂單日期) where rownum<=100 --Oracle

但上述常規(guī)思路要對數據集大排序,運算效率很低挠他。除了常規(guī)思路扳抽,集算器還有更高效的實現(xiàn)方法:使用函數top。

=訂單.top(100;訂單日期)

函數top只排序出訂單日期最早的N條記錄殖侵,然后中斷排序立刻返回贸呢,而不是常規(guī)思路那樣進行全量排序。由于底層模型的限制拢军,SQL不支持這種高性能算法楞陷。

函數top還可應用于計算列,比如擬對訂單采取新的運貨費規(guī)則茉唉,求新規(guī)則下運貨費最大的前100條訂單固蛾,而新規(guī)則是:如果原運貨費大于等于1000,則運貨費打八折度陆。

集算器腳本為:

=訂單.top(-100;if(運貨費>=1000,運貨費*0.8,運貨費))

七艾凯、 關聯(lián)計算

關聯(lián)計算是關系型數據庫的核心算法,在內存計算中應用廣泛坚芜,比如:統(tǒng)計每年每月的訂單數量和訂單金額览芳。

該算法對應Oracle的SQL語句為:

select to_char(訂單.訂單日期,'yyyy') AS 年份,to_char(訂單.訂單日期,'MM') AS 月份斜姥,sum(訂單明細.單價*訂單明細.數量) AS 銷售金額鸿竖,count(1) AS 訂單數量

from 訂單明細 left join 訂單 on 訂單明細.訂單ID=訂單.訂單ID

group by to_char(訂單.訂單日期,'yyyy'),to_char(訂單.訂單日期,'MM')

用集算器實現(xiàn)上述算法時,加載數據的腳本不變铸敏,業(yè)務算法如下(algorithm_2.dfx)

可以看到缚忧,集算器join函數與SQL join語句雖然作用一樣,但結構原理大不相同杈笔。函數join關聯(lián)形成的結果闪水,其字段值不是原子數據類型,而是記錄蒙具,后續(xù)可用“.”號表達關系引用球榆,多層關聯(lián)非常方便。

A2:分組匯總禁筏。

計算結果如下:

關聯(lián)關系分很多類持钉,上述訂單和訂單明細屬于其中一類:主子關聯(lián)。針對主子關聯(lián)篱昔,只需在加載數據時各自按關聯(lián)字段排序每强,業(yè)務算法中就可用歸并算法來提高性能始腾。例如:

=join@m(訂單明細:子表,訂單ID;訂單:主表,訂單ID)

函數join@m表示歸并關聯(lián),只對同序的兩個或多個表有效空执。

集算器的關聯(lián)計算與RDB不同浪箭,RDR對所有類型的關聯(lián)關系都采用相同的算法,無法進行有針對性的優(yōu)化辨绊,而集算器采取分而治之的理念奶栖,對不同類型的關聯(lián)關系提供了不同的算法,可進行有針對性的透明優(yōu)化门坷。

除了主子關聯(lián),最常用的就是外鍵關聯(lián)拜鹤,常用的外鍵表(或字典表)有分類框冀、地區(qū)、城市敏簿、員工明也、客戶等。對于外鍵關聯(lián)惯裕,集算器也有相應的優(yōu)化方法温数,即在數據加載階段事先建立關聯(lián),如此一來業(yè)務算法就不必臨時關聯(lián)蜻势,性能因此提高撑刺,并發(fā)時效果尤為明顯。另外握玛,集算器用指針建立外鍵關聯(lián)够傍,訪問速度更快。

比如這個案例:訂單表的客戶ID字段是外鍵挠铲,對應客戶表(客戶ID冕屯、客戶名稱、地區(qū)拂苹、城市)安聘,需要統(tǒng)計出每個地區(qū)每個城市的訂單數量。

數據加載腳本(initData_3.dfx)如下:

A4:用函數switch建立外鍵關聯(lián)瓢棒,將訂單表的客戶ID字段浴韭,替換為客戶表相應記錄的指針。

業(yè)務算法腳本如下(algorithm_3.dfx)如下

加載數據時已經建立了外鍵指針關聯(lián)脯宿,所以A1中的“客戶ID”表示:訂單表的客戶ID字段所指向的客戶表記錄矿瘦,“客戶ID.地區(qū)”即客戶表的地區(qū)字段伴找。

腳本中多處使用“.”號表達關聯(lián)引用脐恩,語法比SQL直觀易懂,遇到多表多層關聯(lián)時尤為便捷搀继。而在SQL中,關聯(lián)一多如同天書翠语。

上述計算結果如下:

八叽躯、 內外混合計算

內存計算雖然快,但是內存有限肌括,因此通常只駐留最常用点骑、并發(fā)訪問最多的數據,而內存放不下或訪問頻率低的數據谍夭,還是要留在硬盤黑滴,用到的時候再臨時加載,并與內存數據共同參與計算紧索。這就是所謂的內外混合計算袁辈。

下面舉例說明集算器中的內外混合計算。

案例描述:某零售行業(yè)系統(tǒng)中珠漂,訂單明細訪問頻率較低晚缩,數據量較大,沒必要也沒辦法常駐內存∠蔽#現(xiàn)在要將訂單明細與內存里的訂單關聯(lián)起來荞彼,統(tǒng)計出每年每種產品的銷售數量。

數據加載腳本(initData_4.dfx)如下:

業(yè)務算法腳本(algorithm_4.dfx)如下:

A2:執(zhí)行SQL待笑,以游標方式取訂單明細鸣皂,以便計算遠超內存的大量數據。

A3:將訂單表轉為游標模式暮蹂,下一步會用到寞缝。

A4:關聯(lián)訂單明細表和訂單表。函數joinx與join@m作用類似椎侠,都可對有序數據進行歸并關聯(lián)第租,區(qū)別在于前者對游標有效措拇,后者對序表有效我纪。

A5:執(zhí)行分組匯總。

九丐吓、 數據更新

數據庫中的物理表總會變化浅悉,這種變化應當及時反映到共享的內存表中,才能保證內存計算結果的正確券犁,這種情況下就需要更新內存术健。如果物理表較小,那么解決起來很容易粘衬,只要定時執(zhí)行初始化數據腳本(initData.dfx)就可以了荞估。但如果物理表太大咳促,就不能這樣做了,因為初始化腳本會進行全量加載勘伺,本身就會消耗大量時間跪腹,而且加載時無法進行內存計算。例如:某零售巨頭訂單數據量較大飞醉,從數據庫全量加載到內存通常超過5分鐘冲茸,但為保證一定的實時性,內存數據又需要5分鐘更新一次缅帘,顯然轴术,兩者存在明顯的矛盾。

解決思路其實很自然钦无,物理表太大的時候逗栽,應該進行增量更新,5分鐘的增量業(yè)務數據通常很小失暂,增量不會影響更新內存的效率祭陷。

要實現(xiàn)增量更新,就需要知道哪些是增量數據趣席,不外乎以下三種方法:

方法A:在原表加標記字段以識別兵志。缺點是會改動原表。

方法B:在原庫創(chuàng)建一張“變更表”宣肚,將變更的數據記錄在內想罕。好處是不動原表,缺點是仍然要動數據庫霉涨。

方法C:將變更表記錄在另一個數據庫按价,或文本文件Excel中。好處是對原數據庫不做任何改動笙瑟,缺點是增加了維護工作量楼镐。

集算器支持多數據源計算,所以方法B往枷、C沒本質區(qū)別框产,下面就以B為例更新訂單表。

第一步错洁,在數據庫中建立“訂單變更表”秉宿,繼承原表字段,新加一個“變更標記”字段屯碴,當用戶修改原始表時描睦,需要在變更表同步記錄。如下所示的訂單變更表导而,表示新增1條修改2條刪除1條忱叭。

第二步隔崎,編寫集算器腳本updatemem_4.dfx,進行數據更新韵丑。

A1:建立數據庫連接仍稀。

A2:將內存中的訂單復制一份,命名為訂單cp埂息。下面過程只針對訂單cp進行修改技潘,修改完畢再替代內存中的訂單,期間訂單仍可正常進行業(yè)務計算千康。

A3:取數據庫訂單變更表享幽。

A4-B5:取出訂單變更表中需刪除的記錄,在訂單cp中找到這些記錄拾弃,并刪除值桩。

A6-B6:取出訂單變更表中需新增的記錄,在訂單cp中追加豪椿。

A7-B9:這一步是修改訂單cp奔坟,相當于先刪除再追加。也可用modify函數實現(xiàn)修改搭盾。

A10:將修改后的訂單cp常駐內存咳秉,命名為訂單。

A11-A12:清空“變更表”鸯隅,以便下次取新的變更記錄澜建。

上述腳本實現(xiàn)了完整的數據更新,而實際上很多情況下只需要追加數據蝌以,這樣腳本還會簡單很多炕舵。

腳本編寫完成后,還需第三步:定時5分鐘執(zhí)行該腳本跟畅。

定時執(zhí)行的方法有很多咽筋。如果集算器部署為獨立服務,與Web應用沒有共用JVM徊件,那么可以使用操作系統(tǒng)自帶的定時工具(計劃任務或crontab)奸攻,使其定時執(zhí)行集算器命令(esprocx.exe或esprocx.sh)。

有些web應用有自己的定時任務管理工具庇忌,可定時執(zhí)行某個JAVA類舞箍,這時可以編寫JAVA類,用JDBC調用集算器腳本皆疹。

如果web應用沒有定時任務管理工具,那就需要手工實現(xiàn)定時任務占拍,即編寫JAVA類略就,繼承java內置的定時類TimerTask捎迫,在其中調用集算器腳本,再在啟動類中調用定時任務類表牢。

其中啟動類myServle4為:

1. import java.io.IOException;

2. import java.util.Timer;

3. import javax.servlet.RequestDispatcher;

4. import javax.servlet.ServletContext;

5. import javax.servlet.ServletException;

6. import javax.servlet.http.HttpServlet;

7. import javax.servlet.http.HttpServletRequest;

8. import javax.servlet.http.HttpServletResponse;

9. import org.apache.commons.lang.StringUtils;

10. public class myServlet4 extends HttpServlet {

11. private static final long serialVersionUID = 1L;

12. private Timer timer1 = null;

13. private Task task1;

14. public ConvergeDataServlet() {

15. super();

16. }

17. public void destroy() {

18. super.destroy();

19. if(timer1!=null){

20. timer1.cancel();

21. }

22. }

23. public void doGet(HttpServletRequest request, HttpServletResponse response)

24. throws ServletException, IOException {

25. }

26. public void doPost(HttpServletRequest request, HttpServletResponse response)

27. throws ServletException, IOException {

28. doGet(request, response);

29. }

30. public void init() throws ServletException {

31. ServletContext context = getServletContext();

32. // 定時刷新時間(5分鐘)

33. Long delay = new Long(5);

34. // 啟動定時器

35. timer1 = new Timer(true);

36. task1 = new Task(context);

37. timer1.schedule(task1, delay 60 1000, delay 60 1000);

38. }

39. }

定時任務類Task為:

11. import java.util.TimerTask;

12. import javax.servlet.ServletContext;

13. import java.sql.*;

14. import com.esproc.jdbc.*;

15. public class Task extends TimerTask{

16. private ServletContext context;

17. private static boolean isRunning = true;

18. public Task(ServletContext context){

19. this.context = context;

20. }

21. @Override

22. public void run() {

23. if(!isRunning){

24. com.esproc.jdbc.InternalConnection con=null;

25. try {

26. Class.forName("com.esproc.jdbc.InternalDriver");

27. con =(com.esproc.jdbc.InternalConnection)DriverManager.getConnection("jdbc:esproc:local://");

28. ResultSet rs = con.executeQuery("call updatemem_4()");

29. }

30. catch (SQLException e){

31. out.println(e);

32. }finally{

33. //關閉數據集

34. if (con!=null) con.close();

35. }

36. }

37. }

38. }

十窄绒、 綜合示例

下面,通過一個綜合示例來看一下在數據源多樣崔兴、算法復雜的情況下彰导,集算器如何很好地實現(xiàn)內存計算:

案例描述:某B2C網站需要試算訂單的郵寄總費用,以便在一定成本下挑選合適的郵費規(guī)則敲茄。大部分情況下位谋,郵費由包裹的總重量決定,但當訂單的價格超過指定值時(比如300美元)堰燎,則提供免費付運掏父。結果需輸出各訂單郵寄費用以及總費用。

其中訂單表已加載到內存秆剪,如下:

郵費規(guī)則每次試算時都不同赊淑,因此由參數“pRule”臨時傳入,格式為json字符串仅讽,某次規(guī)則如下:

[{"field":"cost","minVal":300,"maxVal":1000000,"Charge":0},

{"field":"weight","minVal":0,"maxVal":1,"Charge":10},

{"field":"weight","minVal":1,"maxVal":5,"Charge":20},

{"field":"weight","minVal":5,"maxVal":10,"Charge":25},

{"field":"weight","minVal":10,"maxVal":1000000,"Charge":40}]

上述json串表示各字段在各種取值范圍內時的郵費陶缺。第一條記錄表示,cost字段取值在300與1000000之間的時候洁灵,郵費為0(免費付運)组哩;第二條記錄表示,weight字段取值在0到1(kg)之間時处渣,郵費為10(美元)伶贰。

思路:將json串轉為二維表,分別找出filed字段為cost和weight的記錄罐栈,再對整個訂單表進行循環(huán)黍衙。循環(huán)中先判斷訂單記錄中的cost值是否滿足免費標準,不滿足則根據重量判斷郵費檔次荠诬,之后計算郵費琅翻。算完各訂單郵費后再計算總郵費,并將匯總結果附加為訂單表的最后一條記錄柑贞。

數據加載過程很簡單方椎,這里不再贅述,即:讀數據庫表钧嘶,并命名為“訂單表”棠众。

業(yè)務算法相對復雜,具體如下:

A1:解析json,將其轉為二維表闸拿。集算器支持多數據源空盼,不僅支持RDB,也支持NOSQL新荤、文件揽趾、webService。

A2-A3:查詢郵費規(guī)則苛骨,分為免費和收費兩種篱瞎。

A4:新增空字段postage。

A5-D8:按兩種規(guī)則循環(huán)訂單表痒芝,計算相應的郵費俐筋,并填入postage字段。這里多處用到流程控制吼野,集算器用縮進表示校哎,其中A5、B7為循環(huán)語句瞳步,C6闷哆、D8跳入下一輪循環(huán),B5单起、C7為判斷語句

A9:在訂單表追加新紀錄抱怔,填入匯總值。

計算結果如下:

至此嘀倒,本文詳細介紹了集算器用作內存計算引擎的完整過程屈留,同時包括了常用計算方法和高級運算技巧〔饽ⅲ可以看到灌危,集算器具有以下顯著優(yōu)點:

l 結構簡單實施方便,可快速實現(xiàn)內存計算碳胳;

l 支持多種調用接口勇蝙,應用集成沒有障礙;

l 支持透明優(yōu)化挨约,可顯著提升計算性能味混;

l 支持多種數據源,便于實現(xiàn)混合計算诫惭;

l 語法敏捷精妙翁锡,可輕松實現(xiàn)復雜業(yè)務邏輯。

關于內存計算夕土,還有個多機分布式計算的話題馆衔,將在后續(xù)文章中進行介紹。?

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哈踱,隨后出現(xiàn)的幾起案子荒适,更是在濱河造成了極大的恐慌梨熙,老刑警劉巖开镣,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異咽扇,居然都是意外死亡邪财,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門质欲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來树埠,“玉大人,你說我怎么就攤上這事嘶伟≡醣铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵九昧,是天一觀的道長绊袋。 經常有香客問我,道長铸鹰,這世上最難降的妖魔是什么癌别? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任展姐,我火速辦了婚禮圾笨,結果婚禮上,老公的妹妹穿的比我還像新娘谍婉。我一直安慰自己穗熬,他們只是感情好,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布箱季。 她就那樣靜靜地躺著藏雏,像睡著了一般掘殴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上病瞳,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音,去河邊找鬼嚎于。 笑死,一個胖子當著我的面吹牛肋僧,可吹牛的內容都是我干的。 我是一名探鬼主播辫诅,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼么夫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腐螟?” 一聲冷哼從身側響起遭垛,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趾盐,失蹤者是張志新(化名)和其女友劉穎救鲤,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片业筏。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡芍秆,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情怀读,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響牡昆,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦楼咳、人聲如沸余耽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春自点,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工设捐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人曙蒸。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓构韵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搓萧。 傳聞我的和親對象是個殘疾皇子瘸洛,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內容