JAVA 开发中常常会遇到不方便使用数据库,但又要进行结构化数据计算的场景。JAVA 晚期没有提供相干类库,即便排序、分组这种根本计算也要硬写代码,开发效率很低。起初 JAVA8 推出了 Stream 库,凭借 Lambda 表达式、链式编程格调、汇合函数,才终于解决了结构化数据计算类库从无到有的问题。
Stream 能够简化结构化数据的计算
比方排序:
Stream<Order> result=Orders
.sorted((sAmount1,sAmount2)->Double.compare(sAmount1.Amount,sAmount2.Amount))
.sorted((sClient1,sClient2)->CharSequence.compare(sClient2.Client,sClient1.Client));
下面代码中的 sorted 是汇合函数,可不便地进行排序。”(参数)-> 函数体 ” 的写法即 Lambda 表达式,能够简化匿名函数的定义。两个 sorted 函数连在一起用属于链式编程格调,能够使多步骤计算变得直观。
Stream 计算能力还不够强
依然以下面的排序为例,sorted 函数只须要晓得排序字段和程序 / 逆序就够了,参考 SQL 的写法 ”…from Orders order by Client desc, Amount”,但实际上还要额定输出排序字段的数据类型。程序 / 逆序用 asc/desc(或 +/-)等符号就能够简略示意了,但这里却要用 compare 函数。另外,理论要排序的字段程序和代码写进去的程序是相同的,有些反直觉。
再比方分组汇总:
Calendar cal=Calendar.getInstance();
Map<Object, DoubleSummaryStatistics> c=Orders.collect(Collectors.groupingBy(
r->{cal.setTime(r.OrderDate);
return cal.get(Calendar.YEAR)+"_"+r.SellerId;
},
Collectors.summarizingDouble(r->{return r.Amount;})
)
);
for(Object sellerid:c.keySet()){DoubleSummaryStatistics r =c.get(sellerid);
String year_sellerid[]=((String)sellerid).split("_");
System.out.println("group is (year):"+year_sellerid[0]+"\t (sellerid):"+year_sellerid[1]+"\t sum is:"+r.getSum()+"\t count is:"+r.getCount());
}
下面代码中,所有呈现字段名的中央,都要先写上表名,即 ” 表名. 字段名 ”,而不能像 SQL 那样省略表名。匿名函数语法简单,随着代码量的减少,复杂度迅速增长。两个匿名函数造成嵌套,代码更难解读。实现一个分组汇总性能要用多个函数和类,包含 groupingBy、collect、Collectors、summarizingDouble、DoubleSummaryStatistics 等,学习老本不低。分组汇总的后果是 Map,而不是结构化数据类型,如果要持续计算,通常要定义新的结构化数据类型,并进行转换类型,处理过程很繁琐。两个分组字段在结构化数据计算中很常见,但函数 grouping 只反对一个分组变量,为了让一个变量代表两个字段,就要采取一些变通技巧,比方新建一个两字段的结构化数据类型,或者把两个字段用下划线拼起来,这让代码变得更加繁琐。
Stream 计算能力有余,起因在于其根底语言 JAVA 是编译型语言,无奈提供业余的结构化数据对象,短少来自底层的无力反对。
JAVA 是编译型语言,返回值的构造必须当时定义,遇到较多的两头步骤时,就要定义多个数据结构,这不仅让代码变得繁琐,还导致参数解决不灵便,要用一套简单的规定来实现匿名语法。解释性语言则人造反对动静构造,还能够不便地将参数表达式指定为值参数或函数参数,提供更简略的匿名函数。
在这种状况下,Kotlin 应运而生。Kotlin 是基于 JAVA 的古代开发语言,所谓古代,重点体现在对 JAVA 语法尤其是 Stream 的改良上,即 Lambda 表达式更加简洁,汇合函数更加丰盛。
Kotlin 计算能力强于 Stream
比方排序:
var resutl=Orders.sortedBy{it.Amount}.sortedByDescending{it.Client}
下面代码毋庸指明排序字段的数据类型,毋庸用函数表白程序 / 逆序,间接援用 it 作为匿名函数的默认参数,而不是刻意定义,整体比 Stream 简短不少。
Kotlin 改良并不大,计算能力依然有余
依然以排序为例,Kotlin 尽管提供了 it 这个默认参数,但实践上只有晓得字段名就够了,没必要带上表名(it)。排序函数只能对一个字段进行排序,不能动静接管多个字段。
再比方分组汇总:
data class Grp(var OrderYear:Int,var SellerId:Int)
data class Agg(var sumAmount: Double,var rowCount:Int)
var result=Orders.groupingBy{Grp(it.OrderDate.year+1900,it.SellerId)}
.fold(Agg(0.0,0),{acc, elem -> Agg(acc.sumAmount + elem.Amount,acc.rowCount+1)
})
.toSortedMap(compareBy<Grp> { it. OrderYear}.thenBy {it. SellerId})
result.forEach{println("group fields:${it.key.OrderYear}\t${it.key.SellerId}\t aggregate fields:${it.value.sumAmount}\t${it.value.rowCount}") }
下面代码中,一个分组汇总的动作,须要用到多个函数,包含简单的嵌套函数。用到字段的中央要带上表名。分组汇总的后果不是结构化数据类型。要当时定义两头后果的数据结构。
如果持续考查汇合、关联等更多的计算,就会发现同样的法则:Kotlin 代码确实比 Stream 短一些,但大都是无关紧要的质变,并未产生粗浅的量变,该有的步骤一个不少。
Kotlin 也不反对动静数据结构,无奈提供业余的结构化数据对象,难以真正简化 Lambda 语法,无奈脱离表名间接援用字段,无奈间接反对动静的多字段计算(比方多字段排序)。
esProc SPL 的呈现,将会彻底改观 JAVA 生态下结构化数据处理的窘境。
esProc SPL 是 JVM 下的开源结构化数据计算语言,提供了业余的结构化数据对象,内置丰盛的计算函数,灵便简洁的语法,易于集成的 JDBC 接口,善于简化简单计算。
SPL 内置丰盛的计算函数实现根底计算
比方排序:=Orders.sort(-Client, Amount)
SPL 毋庸指明排序字段的数据类型,毋庸用函数指明方向 / 逆序,应用字段时毋庸附带表名,一个函数就能够动静地对多个字段进行排序。
分组汇总:=Orders.groups(year(OrderDate),Client; sum(Amount),count(1))
下面的计算结果依然是结构化数据对象,能够直接参与下一步计算。对双字段进行分组或汇总时,也不须要当时定义数据结构。整体代码没有多余的函数,sum 和 count 用法简洁易懂,甚至很难发觉这是嵌套的匿名函数。
更多计算也同样简略:
去重:=Orders.id(Client)
含糊查问:=Orders.select(Amount*Quantity>3000 && like(Client,“S”))
关联:=join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))
SPL 提供了 JDBC 接口,可被 JAVA 代码无缝调用
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String str="=T(\"D:/Orders.xls\"). Orders.groups(year(OrderDate),Client; sum(Amount))";
ResultSet result = statement.executeQuery(str);
SPL 语法格调简洁灵便,具备弱小的计算能力。
SPL 可简化分步计算、有序计算、分组后计算等逻辑较简单的计算,很多 SQL/ 存储过程难以实现的计算,用 SPL 解决起来就很轻松。比方,找出销售额累计占到一半的前 n 个大客户,并按销售额从大到小排序:
除了计算能力,SPL 在零碎架构、数据源、两头数据存储、计算性能上也有一些特有的劣势,这些劣势有助于 SPL 进行库外结构化数据计算。
SPL 反对计算热切换和代码外置,可升高零碎耦合性。
比方,将下面的 SPL 代码存为脚本文件,再在 JAVA 中以存储过程的模式调用文件名:
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("call getClient()");
SPL 是解释型语言,批改后可间接运行,毋庸编译,不用重启 JAVA 服务。SPL 代码外置于 JAVA,通过文件名被调用,不依赖 JAVA 代码,耦合性低。
SPL 反对多种数据源,可进行跨源计算和跨库计算。
SPL 反对各类数据库,txt\csv\xls 等文件,MongoDB、Hadoop、redis、ElasticSearch、Kafka、Cassandra 等 NoSQL,特地地,还反对 WebService XML、Restful Json 等多层数据:
对文本文件和数据库进行跨源关联:
SPL 提供了自有存储格局,可长期或永恒存储数据,并进行高性能计算。
SPL 反对 btx 存储格局,适宜暂存来自于低速数据源的数据,比方 CSV:
btx 体积小,读写速度快,能够像一般文本文件那样进行计算:
=T(“D:/fast.btx”).sort(Client,- Amount)
如果对 btx 进行有序存储,还能取得高计算性能,比方并行计算、二分查找。SPL 还反对更高性能的 ctx 存储格局,反对压缩、列存、行存、分布式计算、大并发计算,适宜长久存储大量数据,并进行高性能计算。
在数据库外的结构化数据计算方面,Stream 做出了突破性的奉献;Kotlin 增强了这种能力,但编译性语言的个性使它无奈走得更远;要想彻底解决库外计算的难题,还须要 SPL 这种业余的结构化数据计算语言。
以上就是分享的全部内容,如果喜爱帮忙点赞分享转发,