一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java 結構化數據處理開源庫 SPL

Java 結構化數據處理開源庫 SPL

2021-12-29 23:14Java知音 Java教程

如果我們在Java中也提供有一套完整的結構化數據處理和計算類庫,那這個問題就能得到解決:即享受到架構的優勢,又不致于降低開發效率。

Java 結構化數據處理開源庫 SPL

現代Java應用架構越來越強調數據存儲和處理分離,以獲得更好的可維護性、可擴展性以及可移植性,比如火熱的微服務就是一種典型。這種架構通常要求業務邏輯要在Java程序中實現,而不是像傳統應用架構中放在數據庫中。

應用中的業務邏輯大都會涉及結構化數據處理。數據庫(SQL)中對這類任務有較豐富的支持,可以相對簡易地實現業務邏輯。但Java卻一直缺乏這類基礎支持,導致用Java實現業務邏輯非常繁瑣低效。結果,雖然架構上有各種優勢,但開發效率卻反而大幅下降了。

如果我們在Java中也提供有一套完整的結構化數據處理和計算類庫,那這個問題就能得到解決:即享受到架構的優勢,又不致于降低開發效率。

需要什么樣的能力?

Java下理想的結構化數據處理類庫應當具備哪些特征呢?我們可以從SQL來總結:

1. 集合運算能力

結構化數據經常是批量(以集合形式)出現的,為了方便地計算這類數據,有必要提供足夠的集合運算能力。

如果沒有集合運算類庫,只有數組(相當于集合)這種基礎數據類型,我們要對集合成員做個簡單地求和也需要寫四五行循環語句才能完成,過濾、分組聚合等運算則要寫出數百行代碼了。

SQL提供有較豐富的集合運算,如 SUM/COUNT 等聚合運算,WHERE 用于過濾、GROUP 用于分組,也支持針對集合的交、并、差等基本運算。這樣寫出來的代碼就會短小很多。

2. Lambda語法

有了集合運算能力是否就夠了呢?假如我們為 Java 開發一批的集合運算類庫,是否就可以達到 SQL 的效果呢?

沒有這么簡單!

以過濾運算為例。過濾通常需要一個條件,把滿足條件的集合成員保留。在 SQL 中這個條件是以一個表達式形式出現的,比如寫 WHERE x>0,就表示保留那些使得 x>0 計算結果為真的成員。這個表達式 x>0 并不是在執行這個語句之前先計算好的,而是在遍歷時針對每個集合成員計算的。本質上,這個表達式本質上是一個函數,是一個以當前集合成員為參數的函數。對于 WHERE 運算而言,相當于把一個用表達式定義的函數用作了 WHERE 的參數。

這種寫法有一個術語叫做 Lambda 語法,或者叫函數式語言。

如果沒有 Lambda 語法,我們就要經常臨時定義函數,代碼會非常繁瑣,還容易發生名字沖突。

SQL中大量使用了 Lambda 語法,不在于必須過濾、分組運算中,在計算列等不必須的場景也可以使用,大大簡化了代碼。

3. 在 Lambda 語法中直接引用字段

結構化數據并非簡單的單值,而是帶有字段的記錄。

我們發現,SQL 的表達式參數中引用記錄字段時,大多數情況可以直接使用字段名稱而不必指明字段所屬的記錄,只有在多個同名字段時才需要冠以表名(或別名)以區分。

新版本的 Java 雖然也開始支持 Lambda 語法了,但只能把當前記錄作為參數傳入這個用 Lambda 語法定義的函數,然后再寫計算式時就總要帶上這個記錄。比如用單價和數量計算金額時,如果用于表示當前成員的參數名為 x,則需要寫成“x. 單價 *x. 數量”這種啰嗦的形式。而在 SQL 中可以更為直觀地寫成 " 單價 * 數量”。

4. 動態數據結構

SQL還能很好地支持動態數據結構。

結構化數據計算中,返回值經常也是有結構的數據,而結果數據結構和運算相關,沒辦法在代碼編寫之前就先準備好。所以需要支持動態的數據結構能力。

SQL中任何一個 SELECT 語句都會產生一個新的數據結構,在代碼中可以隨意添加刪除字段,而不必事先定義結構(類)。Java 這類語言則不行,在代碼編譯階段就要把用到的結構(類)都定義好,原則上不能在執行過程中動態產生新的結構。

5. 解釋型語言

從前面幾條的分析,我們已經可以得到結論:Java 本身并不適合用作結構化數據處理的語言。它的 Lambda 機制不支持特征 3,而且作為編譯型語言,也不能實現特征 4。

其實,前面說到的 Lambda 語法也不太適合采用編譯型語言來實現。編譯器不能確定這個寫到參數位置的表達式是應該當場計算出表達式的值再傳遞,還是把整個表達式編譯成一個函數傳遞,需要再設計更多的語法符號加以區分。而解釋型語言則沒有這個問題,作為參數的表達式是先計算還是遍歷集合成員時再計算,可以由函數本身來決定。

SQL確實是解釋型語言。

引入SPL

Stream是Java8以官方身份推出的結構化數據處理類庫,但并不符合上述的要求。它沒有專業的結構化數據類型,缺乏很多重要的結構化數據計算函數,不是解釋型語言,不支持動態數據類型,Lambda語法的接口復雜。

Kotlin屬于Java生態系統的一部分,它在Stream的基礎上進行了小幅改進,也提供了結構化數據計算類型,但因為結構化數據計算函數不足,不是解釋型語言,不支持動態數據類型,Lambda語法的接口復雜,仍然不是理想的結構化數據計算類庫。

Scala提供了較豐富的結構化數據計算函數,但編譯型語言的特點,也使它不能成為理想的結構化數據計算類庫。

那么,Java生態下還有什么可以用呢?

集算器SPL。

SPL是由Java解釋執行的程序語言,具備豐富的結構化數據計算類庫、接口簡單的Lambda語法和方便易用的動態數據結構,是Java下理想的結構化處理類庫。

豐富的集合運算函數

SPL提供了專業的結構化數據類型,即序表。和SQL的數據表一樣,序表是批量記錄組成的集合,具有結構化數據類型的一般功能,下面舉例說明。

解析源數據并生成序表:

Orders=T("d:/Orders.csv")

按列名從原序表生成新的序表:

Orders.new(OrderID, Amount, OrderDate)

計算列:

Orders.new(OrderID, Amount, year(OrderDate))

字段改名:

Orders.new(OrderID:ID, SellerId, year(OrderDate):y)

按序號使用字段:

Orders.groups(year(_5),_2; sum(_4))

序表改名(左關聯)

join@1(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))

序表支持所有的結構化計算函數,計算結果也同樣是序表,而不是Map之類的數據類型。比如對分組匯總的結果,繼續進行結構化數據處理:

Orders.groups(year(OrderDate):y; sum(Amount):m).new(y:OrderYear, m*0.2:discount)

在序表的基礎上,SPL提供了豐富的結構化數據計算函數,比如過濾、排序、分組、去重、改名、計算列、關聯、子查詢、集合計算、有序計算等。這些函數具有強大的計算能力,無須硬編碼輔助,就能獨立完成計算:

組合查詢:

Orders.select(Amount>1000 && Amount<=3000 && like(Client,"*bro*"))

排序:

Orders.sort(-Client,Amount)

分組匯總:

Orders.groups(year(OrderDate),Client; sum(Amount))

內關聯:

join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))

簡潔的Lambda語法

SPL支持接口簡單的Lambda語法,無須定義函數名和函數體,可以直接用表達式當作函數的參數,比如過濾:

Orders.select(Amount>1000)

修改業務邏輯時,也不用重構函數,只須簡單修改表達式:

Orders.select(Amount>1000 && Amount<2000)

SPL是解釋型語言,使用參數表達式時不必明確定義參數類型,使Lambda接口更簡單。比如計算平方和,想在sum的過程中算平方,可以直觀寫作:

Orders.sum(Amount*Amount)

和SQL類似,SPL語法也支持在單表計算時直接使用字段名:

Orders.sort(-Client, Amount)

動態數據結構

SPL是解釋型語言,天然支持動態數據結構,可以根據計算結果結構動態生成新序表。特別適合計算列、分組匯總、關聯這類計算,比如直接對分組匯總的結果再計算:

Orders.groups(Client;sum(Amount):amt).select(amt>1000 && like(Client,"*S*"))

或直接對關聯計算的結果再計算:

join(Orders:o,SellerId ; Employees:e,Eid).groups(e.Dept; sum(o.Amount))

較復雜的計算通常都要拆成多個步驟,每個中間結果的數據結構幾乎都不同。SPL支持動態數據結構,不必先定義這些中間結果的結構。比如,根據某年的客戶回款記錄表,計算每個月的回款額都在前10名的客戶:

Sales2021.group(month(sellDate)).(~.groups(Client;sum(Amount):sumValue)).(~.sort(-sumValue)) .(~.select(#<=10)).(~.(Client)).isect()

直接執行SQL

SPL中還實現了SQL的解釋器,可以直接執行SQL,從基本的WHERE、GROUP到JOIN、甚至WITH都能支持:

  1. $select * from d:/Orders.csv where (OrderDate<date('2020-01-01') and Amount<=100)or (OrderDate>=date('2020-12-31') and Amount>100)
  1. $select year(OrderDate),Client ,sum(Amount),count(1) from d:/Orders.csv
  2. group by year(OrderDate),Client
  3. having sum(Amount)<=100
  1. $select o.OrderId,o.Client,e.Name e.Dept from d:/Orders.csv o
  2. join d:/Employees.csv e on o.SellerId=e.Eid
  1. $with t as (select Client ,sum(amount) s from d:/Orders.csv group by Client)
  2. select t.Client, t.s, ct.Name, ct.address from t
  3. left join ClientTable ct on t.Client=ct.Client

更多語言優勢

作為專業的結構化數據處理語言,SPL不僅覆蓋了SQL的所有計算能力,在語言方面,還有更強大的優勢:

離散性及其支掛下的更徹底的集合化

集合化是SQL的基本特性,即支持數據以集合的形式參與運算。但SQL的離散性很不好,所有集合成員必須作為一個整體參于運算,不能游離在集合之外。而Java等高級語言則支持很好的離散性,數組成員可以單獨運算。

但是,更徹底的集合化需要離散性來支持,集合成員可以游離在集合之外,并與其它數據隨意構成新的集合參與運算 。

SPL兼具了SQL的集合化和Java的離散性,從而可以實現更徹底的集合化。

比如,SPL中很容易表達“集合的集合”,適合分組后計算。比如,找到各科成績均在前10名的學生:

  A
1 =T("score.csv").group(subject)
2 =A2.(~.rank(score).pselect@a(~<=10))
3 =A1.(~(A3(#)).(name)).isect()
 

SPL序表的字段可以存儲記錄或記錄集合,這樣可以用對象引用的方式,直觀地表達關聯關系,即使關系再多,也能直觀地表達。比如,根據員工表找到女經理下屬的男員工:

Employees.select(性別:"男",部門.經理.性別:"女")

有序計算是離散性和集合化的典型結合產物,成員的次序在集合中才有意義,這要求集合化,有序計算時又要將每個成員與相鄰成員區分開,會強調離散性。SPL兼具集合化和離散性,天然支持有序計算。

具體來說,SPL可以按絕對位置引用成員,比如,取第3條訂單可以寫成Orders(3),取第1、3、5條記錄可以寫成Orders([1,3,5])。

SPL也可以按相對位置引用成員,比如,計算每條記錄相對于上一條記錄的金額增長率:Orders.derive(amount/amount[-1]-1)

SPL還可以用#代表當前記錄的序號,比如把員工按序號分成兩組,奇數序號一組,偶數序號一組:Employees.group(#%2==1)

更方便的函數語法

大量功能強大的結構化數據計算函數,這本來是一件好事,但這會讓相似功能的函數不容易區分。無形中提高了學習難度。

SPL提供了特有的函數選項語法,功能相似的函數可以共用一個函數名,只用函數選項區分差別。比如select函數的基本功能是過濾,如果只過濾出符合條件的第1條記錄,只須使用選項@1:

Orders.select@1(Amount>1000)

數據量較大時,用并行計算提高性能,只須改為選項@m:

Orders.select@m(Amount>1000)

對排序過的數據,用二分法進行快速過濾,可用@b:

Orders.select@b(Amount>1000)

函數選項還可以組合搭配,比如:

Orders.select@1b(Amount>1000)

結構化運算函數的參數常常很復雜,比如SQL就需要用各種關鍵字把一條語句的參數分隔成多個組,但這會動用很多關鍵字,也使語句結構不統一。

SPL支持層次參數,通過分號、逗號、冒號自高而低將參數分為三層,用通用的方式簡化復雜參數的表達:

join(Orders:o,SellerId ; Employees:e,EId)

擴展的Lambda語法

普通的Lambda語法不僅要指明表達式(即函數形式的參數),還必須完整地定義表達式本身的參數,否則在數學形式上不夠嚴密,這就讓Lambda語法很繁瑣。比如用循環函數select過濾集合A,只保留值為偶數的成員,一般形式是:

A.select(f(x):{x%2==0} )

這里的表達式是x%2==0,表達式的參數是f(x)里的x,x代表集合A里的成員,即循環變量。

SPL用固定符號~代表循環變量,當參數是循環變量時就無須再定義參數了。在SPL中,上面的Lambda語法可以簡寫作:A.select(~ %2==0)

普通Lambda語法必須定義表達式用到的每一個參數,除了循環變量外,常用的參數還有循環計數,如果把循環計數也定義到Lambda中,代碼就更繁瑣了。

SPL用固定符號#代表循環變量。比如,用函數select過濾集合A,只保留序號是偶數的成員,SPL可以寫作:A.select(# %2==0)

相對位置經常出現在難度較大的計算中,而且相對位置本身就很難計算,當要使用相對位置時,參數的寫法將非常繁瑣。

SPL用固定形式[序號]代表相對位置:

  A B
1 =T("Orders.txt") /訂單序表
2 =A1.groups(year(Date):y,month(Date):m; sum(Amount):amt) /按年月分組匯總
3 =A2.derive(amt/amt[-1]:lrr, amt[-1:1].avg():ma) /計算比上期和移動平均
 

無縫集成、低耦合、熱切換

作為用Java解釋的腳本語言,SPL提供了JDBC驅動,可以無縫集成進Java應用程中。

簡單語句可以像SQL一樣直接執行:

  1. Class.forName("com.esproc.jdbc.InternalDriver");
  2. Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
  3. PrepareStatement st = conn.prepareStatement("=T(\"D:/Orders.txt\").select(Amount>1000 && Amount<=3000 && like(Client,\"*S*\"))");
  4. ResultSet result=st.execute();
  5. ...

復雜計算可以存成腳本文件,以存儲過程方式調用

  1. Class.forName("com.esproc.jdbc.InternalDriver");
  2. Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
  3. Statement st = connection.();
  4. CallableStatement st = conn.prepareCall("{call splscript1(?, ?)}");
  5. st.setObject(1, 3000);
  6. st.setObject(2, 5000);
  7. ResultSet result=st.execute();
  8. ...

將腳本外置于Java程序,一方面可以降低代碼耦合性,另一方面利用解釋執行的特點還可以支持熱切換,業務邏輯變動時只要修改腳本即可立即生效,不像使用Java時常常要重啟整個應用。這種機制特別適合編寫微服務架構中的業務處理邏輯。

原文地址:https://mp.weixin.qq.com/s/zrWVJ7gBLWuSe7f7xpbRMg

延伸 · 閱讀

精彩推薦
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
主站蜘蛛池模板: 免费看欧美一级特黄a大片一 | 青青久在线视频免费观看 | 欧美专区在线观看 | 91久久青青青国产免费 | 91天堂视频| 67id人成观看免费 | 男人女人插 | 草草视频人人爽 | 俄罗斯bbbbbbbbb大片 | 无人影院在线播放 | 亚洲欧美日韩国产一区二区精品 | ysl千人千色t9t9t9 | 亚洲老头与老太hd | 四虎精品成人免费影视 | 91久久精品国产亚洲 | 99精品国产高清一区二区三区香蕉 | 亚洲天堂在线视频观看 | 4s4s4s4s色大众影视 | 亚洲午夜久久久久国产 | 男人捅女人漫画 | ysav67| 久久热这里只有 精品 | 免看一级一片一在线看 | 99热.com| 九九精品国产兔费观看久久 | 三级全黄裸体 | 久久成人伊人欧洲精品AV | 免费欧美日韩 | 动漫美女被吸乳羞羞小说 | chinese调教踩踏视频 | 色综合天天综合 | 睡男神的这件小事小说在线阅读 | 性色欲情网站IWWW九文堂 | 好奇害死猫在线观看 | 欧美日韩综合一区 | 午夜福利理论片高清在线 | 91精品国产色综合久久不卡蜜 | 色橹橹 | 青青在线观看视频 | 奇米狠狠色 | 97综合久久 |