溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

發(fā)布時(shí)間:2020-06-17 16:53:21 來源:網(wǎng)絡(luò) 閱讀:191 作者:raqsoft 欄目:大數(shù)據(jù)

一 問題背景

絕大多數(shù)的應(yīng)用系統(tǒng)中,一開始數(shù)據(jù)的存儲和計(jì)算基本都是由數(shù)據(jù)庫來完成的,同時(shí)服務(wù)于業(yè)務(wù)交易和報(bào)表查詢;不過在經(jīng)過幾年信息化建設(shè)和數(shù)據(jù)積累后,常常都會遇到數(shù)據(jù)庫壓力變大,從而導(dǎo)致性能瓶頸的問題。

究其原因,往往發(fā)現(xiàn)針對歷史數(shù)據(jù)查詢的報(bào)表在其中占了很大比重。進(jìn)一步分析會發(fā)現(xiàn),這類報(bào)表通常都有如下特征:

1、數(shù)據(jù)變化?。汗┎樵兊臍v史數(shù)據(jù)幾乎不再發(fā)生變化;

2、數(shù)據(jù)量大:數(shù)據(jù)量隨時(shí)間不斷增加;

由于大多數(shù)數(shù)據(jù)庫的JDBC性能都很低下(JDBC取數(shù)過程要做數(shù)據(jù)對象轉(zhuǎn)換,比從文件中讀取數(shù)據(jù)會慢一個(gè)數(shù)量級),如果數(shù)據(jù)始終存放在數(shù)據(jù)庫中,當(dāng)涉及數(shù)據(jù)量較大或并發(fā)較多的時(shí)候,報(bào)表的性能會急劇下降,進(jìn)一步還會嚴(yán)重影響相關(guān)的業(yè)務(wù)操作,如市場營銷、數(shù)據(jù)整理再匯報(bào)等。

針對這一問題,常見的解決方案是在生產(chǎn)庫和應(yīng)用之間再增加一個(gè)前置數(shù)據(jù)庫,利用ETL工具定時(shí)從生產(chǎn)庫中提取數(shù)據(jù),清洗后再導(dǎo)入到前置數(shù)據(jù)庫中,所有的歷史報(bào)表查詢都基于前置數(shù)據(jù)庫,從而和生產(chǎn)庫分離,緩解生產(chǎn)庫壓力。

不過這種方案增加了很多不必要的成本、多余的組件和工作量,同時(shí)也加大了后期的管理和維護(hù)難度;更為重要的是,當(dāng)數(shù)據(jù)量比較大時(shí),報(bào)表查詢還是很慢,因?yàn)樯厦嬉呀?jīng)提到過的根本問題并沒有得到解決,大多數(shù)數(shù)據(jù)庫的IO性能遠(yuǎn)低于文件系統(tǒng),而報(bào)表性能又嚴(yán)重依賴于數(shù)據(jù)庫取數(shù)環(huán)節(jié),也就是說,沒能從根子上解決問題。

二 解決思路

要從根子上解決問題,我們可以假設(shè)如果文件擁有計(jì)算能力的話,將這些變化不大的歷史數(shù)據(jù)搬出數(shù)據(jù)庫,采用文件系統(tǒng)存儲,而不是前置數(shù)據(jù)庫,那么將可能獲得比數(shù)據(jù)庫高得多的IO性能,這樣不僅能夠解決大數(shù)據(jù)量報(bào)表查詢慢的難題,我們還將獲得如下這些好處:

1、管理方便;文件天然支持多級目錄,而且復(fù)制、轉(zhuǎn)移、拆分都比數(shù)據(jù)庫簡單、高效得多,這樣,用戶就可以按照業(yè)務(wù)模塊、時(shí)間順序等規(guī)則分類管理數(shù)據(jù),在應(yīng)用程序下線時(shí),也可以按照目錄刪除該應(yīng)用對應(yīng)的數(shù)據(jù)。數(shù)據(jù)管理因此變得簡單清晰,工作量顯著降低。

2、成本低廉;既然是文件,那就可以簡單地存儲在廉價(jià)硬盤中,無需購買昂貴的數(shù)據(jù)庫專用軟硬件。

3、降低數(shù)據(jù)庫擴(kuò)容壓力;數(shù)據(jù)庫吞吐負(fù)擔(dān)降低,就可以顯著推遲擴(kuò)容臨界點(diǎn)的到來,數(shù)據(jù)庫可以繼續(xù)服役,也可以節(jié)省大量的擴(kuò)容成本。

4、資源利用率高;用文件來存儲數(shù)據(jù)并非要拋棄數(shù)據(jù)庫,相反的,文件應(yīng)當(dāng)只存儲安全要求不高、但數(shù)據(jù)量巨大的外圍數(shù)據(jù)以及庫外文件,而數(shù)據(jù)庫仍然存儲核心數(shù)據(jù)。如此一來,文件存儲和數(shù)據(jù)庫存儲各司其職,資源利用率顯著提高。

那么,如何才能有效地為文件賦予計(jì)算能力呢?下面將要介紹的潤乾集算器,就是這樣一款利器,通過集算器,可以實(shí)現(xiàn)復(fù)雜計(jì)算與報(bào)表展現(xiàn)的分離,其內(nèi)置的集算引擎可以使文件擁有計(jì)算能力,輕松應(yīng)對各種疑難雜癥。下圖顯示了常規(guī)情況和引入集算器后的報(bào)表系統(tǒng)結(jié)構(gòu)對比,應(yīng)該說,引入集算器后,整個(gè)體系架構(gòu)變得更加清新與合理了:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

三 場景說明

接下來,我們通過一個(gè)典型的場景來說明集算器的作用和用法:

A表“商品銷售明細(xì)”的數(shù)據(jù)量上億,其中字段areaid與B表“區(qū)域表”的主鍵id關(guān)聯(lián)。A表稱為事實(shí)表,B表稱為維表。A表中與B表主鍵關(guān)聯(lián)的字段稱為A指向B的外鍵,B也稱為A的外鍵表。外鍵表是多對一的關(guān)系。如下圖示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

下面,我們就通過制作“各區(qū)域銷售員每日銷售額日增長率報(bào)表”,來看一下集算器是如何利用文件實(shí)現(xiàn)數(shù)據(jù)外置,從而提升報(bào)表查詢效率的。報(bào)表最終的展示效果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

在這張報(bào)表中,根據(jù)選擇開始日期、結(jié)束日期進(jìn)行查詢,報(bào)表先按照區(qū)域名稱、銷售員代碼、銷售日進(jìn)行分組,統(tǒng)計(jì)每個(gè)銷售員每天的銷售額,以及每個(gè)銷售員每天銷售額的日增長率(算法為“(當(dāng)日銷售額-上一日的銷售額)/上一日的銷售額”)。報(bào)表上部的查詢按鈕是報(bào)表工具提供的“參數(shù)模板”功能,具體做法參見教程,這里不再贅述。

3.1設(shè)計(jì)數(shù)據(jù)存儲組織

在利用文件系統(tǒng)存儲數(shù)據(jù)的諸多優(yōu)勢之前,我們首先應(yīng)該先定義文件的目錄存儲結(jié)構(gòu):

歷史數(shù)據(jù)的特征是交易成型后數(shù)據(jù)落地不再變化,而且數(shù)據(jù)量龐大,由此我們可以將每年的數(shù)據(jù)按照業(yè)務(wù)模塊、月份等規(guī)則進(jìn)行劃分,即每個(gè)月份的數(shù)據(jù)存一份集文件(集文件利用集算器提供的壓縮格式,具有更好IO性能)。目錄結(jié)構(gòu)就是:/業(yè)務(wù)模塊/數(shù)據(jù)明細(xì)表/年月文件名,如下圖所示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

同時(shí),我們還需要設(shè)定每天凌晨時(shí)段定時(shí)執(zhí)行數(shù)據(jù)同步腳本,把前一天的數(shù)據(jù)追加到當(dāng)月集文件中;而在每月1號,腳本還會根據(jù)規(guī)則自動(dòng)生成一個(gè)新的以年月命名的集文件。

3.2同步數(shù)據(jù)

3.2.1同步歷史數(shù)據(jù)到文件

先把2017年1到10月的歷史數(shù)據(jù)按不同月份搬出來(假定已有10個(gè)月的歷史數(shù)據(jù)),集算器的SPL腳本如下:


A

B

C

1

=connect("demo")



2

=10.("SELECT   * FROM sdrpts WHERE filedate>='2017-"/~/"-01'AND   filedate<'2017-"/(~+1)/"-01'")

3

for A2

=file("D:/進(jìn)銷存/商品銷售明細(xì)/2017"+string(#A3,”00”))

4


=A1.cursor(A3)

>B3.export@ab(B4)

5

>A1.close()



A1:連接數(shù)據(jù)庫

A2:生成由10個(gè)SQL組成的集合,每個(gè)SQL分別查詢當(dāng)月(1到10)范圍內(nèi)的數(shù)據(jù)。寫法上,“10.”表示從1循環(huán)到10,在括號內(nèi)的字符串中用相應(yīng)的1到10替換 ~符號。

A3:按照A2中的序列循環(huán)執(zhí)行

B3:按路徑打開每月數(shù)據(jù)的集文件,路徑命名規(guī)則是4位年和2位月,利用string()函數(shù)進(jìn)行格式化,其中#號代表循環(huán)序號

B4:根據(jù)每段sql創(chuàng)建數(shù)據(jù)庫游標(biāo)

C4:將游標(biāo)執(zhí)行計(jì)算后的結(jié)果寫入到集文件中。其中export()函數(shù)使用了@ab的選項(xiàng),@b代表寫成集文件格式,而由于在for循環(huán)里面,需要執(zhí)行多次,所以用@a指明追加方式,把結(jié)果逐步保存到文件中,保證文件的完整性。循環(huán)生成完之后,文件的存儲目錄結(jié)構(gòu)如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A5:關(guān)閉數(shù)據(jù)庫連接


3.2.2同步昨天數(shù)據(jù)到文件

編寫單次執(zhí)行腳本,獲取昨天的歷史數(shù)據(jù)追加到當(dāng)月集文件中,每天執(zhí)行,當(dāng)下月1號時(shí),會自動(dòng)生成新文件,腳本如下:


A

B

C

1

=after(date(now()),-1)

=year(A1)

=month(A1)

2

=file("D:/進(jìn)銷存/商品銷售明細(xì)/"+string(B1)+string(C1,”00”))


3

=connect("demo")

=A3.cursor("SELECT   * FROM sdrpts WHERE DATE_FORMAT(fildate,'%Y-%m-%d')=?",A1)

>A2.export@ab(B3)

4

>A3.close()



A1:根據(jù)當(dāng)前系統(tǒng)時(shí)間,獲取昨天的日期

B1-C1:分別獲取到年、月

A2:按路徑打開需要導(dǎo)出的集文件,路徑規(guī)則是以4位年2位月命名,利用string()函數(shù)進(jìn)行格式化

A3:連接數(shù)據(jù)庫

B3:根據(jù)sql創(chuàng)建數(shù)據(jù)庫游標(biāo),獲取昨日數(shù)據(jù),參數(shù)為昨天日期

C3:執(zhí)行結(jié)果追加寫入到集文件中

A4:關(guān)閉數(shù)據(jù)庫

3.3日志追溯

在上面的步驟中,已經(jīng)可以同步昨天的歷史數(shù)據(jù)到集文件中;但總是有意外情況發(fā)生,假如歷史數(shù)據(jù)沒有同步成功怎么辦呢?我們是不是可以通過記錄日志信息的方式,追溯歷史原因?這樣能夠及時(shí)發(fā)現(xiàn)問題,及時(shí)采取補(bǔ)救措施;比如:很小概率下腳本可能會執(zhí)行失敗,這時(shí)如果及時(shí)發(fā)現(xiàn),就可以先手動(dòng)執(zhí)行腳本重新生成集文件,然后再排查原因,從而避免影響業(yè)務(wù)查詢。(由于集文件目前不支持回滾動(dòng)作,一旦導(dǎo)出出錯(cuò),需要重新導(dǎo)出數(shù)據(jù)生成當(dāng)月集文件。集算器高版本的組表支持回滾,以后會有專門的文章詳細(xì)介紹)。


3.3.1構(gòu)造日志表

第一步,可以先在數(shù)據(jù)庫中定義一張日志表,包含五個(gè)字段(事件名稱/狀態(tài)/異常信息/執(zhí)行時(shí)間/執(zhí)行時(shí)長),數(shù)據(jù)結(jié)構(gòu)如下圖示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

第二步,在集算器腳本中定義4個(gè)參數(shù)名,分別是事件名稱/狀態(tài)/異常信息/執(zhí)行時(shí)長,參數(shù)定義如下圖所示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

第三步,當(dāng)集算器腳本接收來自外界參數(shù)信息時(shí),將參數(shù)值填寫到日志表中:


A

1

=connect("demo")

2

=A1.execute("INSERT   INTO sys_dfx_task_log (task_name,status,error_msg,excute_time,sec_num) VALUES   (?,?,?,?,?)",taskName,status,errorMsg,now(),secNum)

3

>A1.close()

A1:連接數(shù)據(jù)庫

A2:接收來自外界傳入的參數(shù)值后,向數(shù)據(jù)庫的日志表中執(zhí)行SQL插入語句,包含五個(gè)字段(事件名稱/狀態(tài)/異常信息/執(zhí)行時(shí)間/執(zhí)行時(shí)長),其中now()函數(shù)代表獲取當(dāng)期時(shí)間

A3:關(guān)閉數(shù)據(jù)庫


3.3.2設(shè)定日志規(guī)則

我們將判斷同步操作是否成功的規(guī)則設(shè)定為:當(dāng)每天定時(shí)導(dǎo)出到集文件的數(shù)據(jù)條數(shù)與查詢出來需要同步數(shù)據(jù)的總條數(shù)相差小于5條的時(shí)候,我們認(rèn)為同步動(dòng)作是成功的,否則認(rèn)定同步失敗,然后把關(guān)鍵信息寫入到日志表中。按此規(guī)則改造同步數(shù)據(jù)的集算器腳本如下:


A

B

C

1

=after(date(now()),-1)

=year(A1)

=month(A1)

2

=file("D:/進(jìn)銷存/商品銷售明細(xì)/

"+string(B1)+string(C1,”00”))

=now()

=A2.cursor@b().skip()

3

=connect("demo")

=A3.cursor("SELECT   * FROM sdrpts WHERE DATE_FORMAT(fildate,'%Y-%m-%d')=?",A1)

>A2.export@ab(B3)

4

=A3.query("SELECT   COUNT(1) FROM sdrpts WHERE DATE_FORMAT(fildate,'%Y-%m-%d')=?",A1)

=A2.cursor@b().skip()-C2

=interval@ms(B2,now())

5

if A4.#1-B4<5

>call("log.dfx","同步sdrpts"+string(A1)+"的數(shù)據(jù)完成,總記錄條數(shù):"+string(A4.#1)+"總計(jì)導(dǎo)出:"+string(B4),"完成","",C4/1000)

6

else

>call("log.dfx","同步sdrpts"+string(A1)+"的數(shù)據(jù),導(dǎo)出的數(shù)據(jù)量跟數(shù)據(jù)庫中的相差超過5條","失敗","",0)

7

>A3.close()



前面已經(jīng)解釋過的格子的代碼這里不再贅述。

B2:獲取當(dāng)前系統(tǒng)時(shí)間,用于后面計(jì)算導(dǎo)出操作的執(zhí)行時(shí)長

C2:統(tǒng)計(jì)寫入前集文件的記錄數(shù)

A4:執(zhí)行sql查詢需要同步的昨天的數(shù)據(jù)總條數(shù)

B4:當(dāng)數(shù)據(jù)追加寫入到集文件后,再統(tǒng)計(jì)一遍記錄數(shù),同時(shí)減去寫入前的數(shù)量,得到實(shí)際寫入成功的記錄條數(shù)

C4:計(jì)算整個(gè)同步過程的執(zhí)行時(shí)長,其中interval()函數(shù)通過選項(xiàng)@ms指定返回毫秒數(shù)

A5:判斷數(shù)據(jù)庫中需要同步數(shù)據(jù)的總條數(shù)與導(dǎo)出到集文件的數(shù)據(jù)總條數(shù),兩者之差小于5條時(shí),認(rèn)為任務(wù)是執(zhí)行成功的,在日志表中寫入成功記錄,否則認(rèn)定任務(wù)執(zhí)行失敗,在日志表中寫入失敗記錄。

B5-B6:根據(jù)執(zhí)行成功或失敗的判斷,log.dfx網(wǎng)格文件,在日志表中寫入相應(yīng)的記錄。

A7:關(guān)閉數(shù)據(jù)庫


3.3.3查詢?nèi)罩緢?bào)表

為了方便管理,我們還可以通過報(bào)表工具,做一張關(guān)于日志信息的查詢報(bào)表,這樣就能通過web端及時(shí)發(fā)現(xiàn)問題、解決問題,效果如下:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

3.4定時(shí)任務(wù)


3.4.1利用 Quartz


Quartz 是 OpenSymphony開源組織在Job scheduling領(lǐng)域的一個(gè)開源組件,利用Quartz可以簡便地創(chuàng)建定時(shí)執(zhí)行任務(wù),而集算器原本就是獨(dú)立的計(jì)算引擎,兩者結(jié)合起來,再提供一些可視化的配置和管理頁面,就能比較容易的實(shí)現(xiàn)輕量級ETL的功能。如下圖所示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

3.4.2使用操作系統(tǒng)工具創(chuàng)建計(jì)劃任務(wù)

windows操作系統(tǒng)下,可以利用自帶的任務(wù)計(jì)劃程序?qū)崿F(xiàn)定時(shí)任務(wù),比如可以先新建一個(gè)bat文件,寫入需要執(zhí)行的命令:

@echo off

"D:/esProc/bin/esprocx.exe" C:/20180713/synclastday.dfx

再配置一個(gè)計(jì)劃任務(wù)定時(shí)執(zhí)行即可,如下圖所示:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

 

而在Linux操作系統(tǒng)下,可以借助crontab實(shí)現(xiàn)定時(shí)任務(wù),命令如下:   /raqsoft/esProc/bin/esprocx.sh /esproc/synclastday.dfx

3.5數(shù)據(jù)查詢

前面是一個(gè)比較完整 ETL 數(shù)據(jù)準(zhǔn)備過程,下面我們將在這些準(zhǔn)備工作的基礎(chǔ)上,完成“各區(qū)域銷售員每日銷售額日增長率報(bào)表”的制作,通過集算器利用文件實(shí)現(xiàn)數(shù)據(jù)外置,從而提升報(bào)表查詢效率。


3.5.1查詢一個(gè)月內(nèi)數(shù)據(jù)

我們先通過傳入開始日期、結(jié)束日期,只查詢一個(gè)月內(nèi)的數(shù)據(jù),也就是訪問某個(gè)月的集文件即可。(值得一提的是:集算器不僅能夠降低復(fù)雜業(yè)務(wù)運(yùn)算的實(shí)現(xiàn)難度,同時(shí),對于單文件的運(yùn)算還提供了“簡單SQL”方式,讓懂SQL的用戶對文件的操作更容易上手。簡單SQL的特性不是本文的重點(diǎn),有興趣的讀者可以參考相關(guān)文檔,這里不再贅述。)

第一步,分組匯總;根據(jù)起止日期過濾后,按照區(qū)域ID、銷售、日期分組,并匯總銷售金額(銷售數(shù)量*單價(jià)),同時(shí)區(qū)域ID,需要顯示成區(qū)域名稱。編寫集算器腳本如下:


A

1

=connect("demo")

2

=A1.query@x("SELECT   id,city FROM area")

3

=file("D:/進(jìn)銷存/商品銷售明細(xì)/

"+string(year(Bfiledate))+string(month(Bfiledate),”00”)).cursor@b()

4

=A3.select(filedate>=Bfiledate   && filedate<Efiledate)

5

>A4.switch(areaid,A2:id)

6

=A4.groups(areaid,account,date(filedate):filedate;sum(salqty*salamt):subtotal)

7

=A6.new(areaid.city:areaname,account,filedate,subtotal)

8

return A7

A1:連接數(shù)據(jù)庫

A2:通過SQL查詢外鍵表area,共兩個(gè)字段id,city,其中函數(shù)query()使用了@x選項(xiàng),代表查詢結(jié)束時(shí)自動(dòng)關(guān)閉數(shù)據(jù)庫連接,執(zhí)行結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A3:打開集文件對象,根據(jù)文件創(chuàng)建游標(biāo)返回,其中cursor()函數(shù)使用@b選項(xiàng)代表從集文件中讀取。我們事先在腳本設(shè)置中定義了2個(gè)參數(shù),開始日期、結(jié)束日期,如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

這里根據(jù)傳入的開始日期參數(shù)Bfiledate,就能夠準(zhǔn)確的找到指定的集文件對象,比如:當(dāng)Bfiledate的參數(shù)值為2017-09-01時(shí),分別獲取年、月,拼在一起就是集文件的名稱,全路徑為:D:/進(jìn)銷存/商品銷售明細(xì)/201709

A4:通過起止日期過濾出符合條件的記錄

A5:通過switch()函數(shù)在A4表的areaid字段上建立指向A2表中id字段的指針引用記錄,實(shí)現(xiàn)關(guān)聯(lián),如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A6:按區(qū)域ID、銷售、日期分組,并匯總銷售金額(銷售數(shù)量*單價(jià))

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A7:計(jì)算字段值,生成新序表;其中利用A5建立的關(guān)聯(lián)關(guān)系通過“外鍵字段.維表字段”的方式進(jìn)行引用,用 “areaid.city”生成新的字段areaname,(將維表記錄看做外鍵的的屬性,這便是外鍵屬性化的由來),返回關(guān)聯(lián)后的結(jié)果集如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

 

第二步,計(jì)算銷售日增長率;在第一步的基礎(chǔ)上,計(jì)算出每個(gè)區(qū)域下每個(gè)銷售員每天銷售額的日增長率; 修改后的腳本如下:


A

1

=connect("demo")

2

=A1.query@x("SELECT   id,city FROM area")

3

=file("D:/進(jìn)銷存/商品銷售明細(xì)/

"+string(year(Bfiledate))+string(month(Bfiledate),”00”)).cursor@b()

4

=A3.select(filedate>=Bfiledate   && filedate<Efiledate)

5

>A4.switch(areaid,A2:id)

6

=A4.groups(areaid,account,date(filedate):filedate;sum(salqty*salamt):subtotal,sum(0):rate)

7

=A6.run(if(areaid==areaid[-1]&&account==account[-1],rate=(subtotal-subtotal[-1])/subtotal[-1]))

8

=A7.new(areaid.city:areaname,account,filedate,subtotal,rate)  

9

return A8

前面已經(jīng)解釋過的格子代碼這里不再贅述。

A6:按區(qū)域ID、銷售、日期分組,并匯總銷售金額(銷售數(shù)量*單價(jià)),同時(shí)構(gòu)造一個(gè)空的列叫rate,結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

   A7:在A6分組后的基礎(chǔ)上,針對每一行記錄,判斷相鄰行的areaid、account是否相等,相等的情況下,計(jì)算銷售員每天的銷售額的日增長率,算法為“(當(dāng)日銷售額-上一日的銷售額)/上一日的銷售額”。可以看到,集算器用subtotal[-1]來表示上一日的銷售額,可以輕松進(jìn)行相對位置的計(jì)算。

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A8:返回關(guān)聯(lián)后結(jié)果集如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A9:返回結(jié)果集給報(bào)表工具


3.5.2查詢跨月 / 跨年數(shù)據(jù)

上一步已經(jīng)實(shí)現(xiàn)了計(jì)算每個(gè)銷售員銷售額的日增長率,不過只能在一個(gè)集文件中查詢,也就是只能查詢一個(gè)月的數(shù)據(jù)。那如何跨多個(gè)集文件,從而實(shí)現(xiàn)跨月、跨年,適用于大數(shù)據(jù)量的報(bào)表查詢呢?

首先,我們需要寫一個(gè)工具腳本,主要功能是能夠根據(jù)傳入的開始日期、結(jié)束日期,過濾出需要查詢跨月度范圍的多個(gè)集文件路徑,同時(shí)判斷路徑下的集文件對象是否存在。腳本如下:


A

1

=periods@m(startDate,endDate,1)

2

=A1.(path+string(year(~))+string(month(~),”00”))

3

=A2.id()

4

=A3.select(file(~).exists())

5

return A4

腳本接收3個(gè)參數(shù),起止日期,集文件的存儲路徑,如下圖:

 

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

   A1:根據(jù)起止日期,按月間隔獲取日期,其中periods()函數(shù)的選項(xiàng)@m代表按月間隔計(jì)算,比如,開始日期:2017-01-03,結(jié)束日期:2017-11-23,執(zhí)行結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

   A2:循環(huán)A1,通過集文件的存儲路徑與該日期段內(nèi)的年月進(jìn)行拼接。月份要始終保持兩位,利用string()函數(shù)進(jìn)行格式化,結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A3:去重,執(zhí)行結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

A4:判斷路徑下的文件是否真實(shí)存在,由A5返回實(shí)際存在的文件路徑,結(jié)果如下圖:

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

然后,我們需要對上面數(shù)據(jù)查詢的腳本做一些改造,值得注意的是這里將采用多路游標(biāo)的概念,將多個(gè)游標(biāo)合并成一個(gè)游標(biāo)使用,改造后的腳本如下:


A

B

C

D

1

=connect("demo")

=[]



2

=A1.query@x("SELECT   id,city FROM area")



3

=call("D:/進(jìn)銷存/商品銷售明細(xì)/判斷讀取文件的范圍.dfx",Bfiledate,Efiledate,"D:/進(jìn)銷存/商品銷售明細(xì)/")

4

for A3

=file(A4)

=B4.cursor@b()

>B1=B1|C4

5

=B1.mcursor()




6

=A5.select(filedate>=Bfiledate   && filedate<Efiledate)


7

>A6.switch(areaid,A2:id)




8

=A6.groups(areaid,account,date(filedate):filedate;sum(salqty*salamt):subtotal,sum(0):rate)

9

=A8.run(if(areaid==areaid[-1]   && account==account[-1],rate=(subtotal-subtotal[-1])/subtotal[-1]))

10

=A9.new(areaid.city:areaname,account,filedate,subtotal,rate)


11

return A10




 

前面已經(jīng)解釋過的格子代碼這里不再贅述。

A3:調(diào)用”判斷讀取文件的范圍.dfx”,傳入腳本參數(shù)開始日期、結(jié)束日期的值,獲得起止日期內(nèi)的所有集文件的集合

A4-C4:循環(huán)A3,分別打開每個(gè)集文件對象,根據(jù)文件創(chuàng)建游標(biāo),其中cursor()函數(shù)使用@b選項(xiàng)代表從集文件中讀取。

D4:將多個(gè)游標(biāo)對象保存到B1預(yù)留的序列中

A5:利用集算器提供的多路游標(biāo)概念,把數(shù)據(jù)結(jié)構(gòu)相同的多個(gè)游標(biāo)合并成一個(gè)游標(biāo)使用。使用時(shí),多路游標(biāo)采用并行計(jì)算來處理各個(gè)游標(biāo)的數(shù)據(jù),可以通過設(shè)置cs.mcursor(n) 函數(shù)中的n來決定并行數(shù),當(dāng)n空缺時(shí),將按默認(rèn)自動(dòng)設(shè)置并行數(shù)。

A11:最后返回結(jié)果集給報(bào)表工具使用,而結(jié)果集的計(jì)算過程A6到A10與前面一個(gè)集文件時(shí)完全一樣。

3.6作為報(bào)表數(shù)據(jù)源

利用集算器完成了數(shù)據(jù)查詢工作后,可以在報(bào)表中直接將集算器設(shè)置為數(shù)據(jù)源,和使用數(shù)據(jù)庫一樣簡單地完成報(bào)表呈現(xiàn),具體做法包括:

1、在報(bào)表中定義參數(shù)(Bfiledate、Efiledate),

2、設(shè)置集算器數(shù)據(jù)集,并傳遞報(bào)表參數(shù),

3、設(shè)計(jì)報(bào)表表樣

如下圖所示。隨后,輸入?yún)?shù)計(jì)算,即可得到希望的報(bào)表了。

基于文件系統(tǒng)實(shí)現(xiàn)可追加的數(shù)據(jù)集市

如果再結(jié)合文章<<秒級展現(xiàn)的百萬級大清單報(bào)表怎么做>>,那么基本上就可以輕松應(yīng)對項(xiàng)目中遇到的各類大數(shù)據(jù)集報(bào)表、大清單列表了。

3.7總結(jié)

1、簡易版、輕量級ETL

集算器是獨(dú)立的計(jì)算引擎,搭配上定時(shí)執(zhí)行程序,很容易就能實(shí)現(xiàn)簡單、輕量級的ETL功能。

2、高性價(jià)比、高性能

無需構(gòu)建數(shù)倉,很好的解決關(guān)系型數(shù)據(jù)庫中數(shù)據(jù)量大而導(dǎo)致的報(bào)表慢的難題。

3、不影響原有系統(tǒng)構(gòu)架、實(shí)現(xiàn)簡單、易維護(hù)

使用潤乾集算器的集文件存儲大表數(shù)據(jù),獨(dú)立于原有系統(tǒng)構(gòu)架,將原有數(shù)據(jù)水平切割,顯著提高查詢效率,不影響業(yè)務(wù)操作。

4、降低應(yīng)用耦合度

集算器腳本、集文件、報(bào)表模板等可以隨應(yīng)用一起管理和維護(hù),完全和數(shù)據(jù)庫解耦合,數(shù)據(jù)管理因此變得簡單清晰。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI