计算处理 Json 的 Java 开源库 esProc SPL

 

esProc SPL是强大的开源计算引擎,可以方便地处理json相关的运算。

下载、安装、集成

源代码在这里:github.com/SPLWare/esProc,不过从源码编译比较麻烦,官方提供了已经编译好的安装包,可以从c.raqsoft.com.cn/article/1595816810031下载,如果这个链接失效,则可以搜索esProc SPL找到官网下载

安装之后,在 [安装目录]\esProc\lib下可以找到Java集成需要的3jar包:

esproc-bin-xxxx.jar	esProc SPL及其JDBC驱动包
icu4j_60.3.jar		处理国际化
jdom-1.1.3.jar		解析配置文件

将上述jar包引入自己的Java项目,就可以通过JDBC接口执行SPL代码了:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("=1");
result.next();
int IntResult=results.getInt(1);

上述代码能正常执行,并且在 IntResult 中可以提到结果 1,就说明集成成功了。

基本Json运算

现在就可以用SPL处理Json了。

先试个简单的情况strJsonJava里的Json字符串变量,部分内容:

[
	{"OrderID":32,"Client":"JFS","SellerId":3,"Amount":468.0,"OrderDate":"2009-08-13"}
	{"OrderID": 70,"Client": "DSG","SellerId": 7,"Amount": 288,"OrderDate": "2009-09-30"}, 
	{"OrderID": 131,"Client": "FOL","SellerId": 7,"Amount": 103.2,"OrderDate": "2009-12-10"},
	...    
]

Java 将该字符串传给 SPL,由 SPL 进行分组汇总:

PreparedStatement pstmt = connection.prepareStatement("=json(?).groups(Client;sum(Amount):amt, count(1):cnt)");
pstmt.setString(1,strJson);
ResultSet result =pstmt.executeQuery();

可以像常规调用数据库 SQL 一样,在语句中用? 传递参数,只不过用的语句不是 SQL 了。
查看返回的 result,可以看到计算结果如下:

Client	amt	cnt	
ARO	899.0	1	
BDR	4278.8	4	
BON	2564.4	1	
…

上面返回表格形式的ResultSet也可以返回成Json

PreparedStatement pstmt = connection.prepareStatement("=json(json(?).groups(Client;sum(Amount):amt, count(1):cnt))");
pstmt.setString(1,strJson);
ResultSet result  =pstmt.executeQuery();
result.next();
String strResult=results.getString(1);

计算结果:
[{“Client”:“HDR”,“amt”:21040.0,“cnt”:21},{“Client”:“IBM”,“amt”:19030,“cnt”:19},…]

来自文件的Json就更简单了。用SPL代码读同样内容的Json文件,并进行分组汇总:

statement.executeQuery("=json(file(\"d:/orders.json\").read()).groups(Client;sum(Amount):amt, count(1):cnt)");

可以得到同样的计算结果。

SPL支持丰富的字符串和日期函数。比如:过滤出年份为2021年,且客户名包含指定字符串的订单(后续只写SPL代码):

=json(file(\"d:/orders.json\").read()).conj(Orders).select(year(OrderDate)==2012 && like@c(Client,"*business*"))

更多的计算函数和语法可以去参考官网文档,大多数常规运算都只要一句就能搞定。

进阶Json计算

计算多层Json

json经常是多层的,比如这样一段json,上层是员工记录,下层是员工的订单记录:

[{
    "EId": 7,"State": "Illinois","Dept": "Sales","Name": "Alexis","Gender": "F","Salary": 9000,"Birthday": "1972-08-16",
    "Orders": [
	{"OrderID": 70,"Client": "DSG","SellerId": 7,"Amount": 288,"OrderDate": "2009-09-30"}, 
	{"OrderID": 131,"Client": "FOL","SellerId": 7,"Amount": 103.2,"OrderDate": "2009-12-10"}
    ]
}
{
"EId": 8,"State": "California",
 ...
}]

计算目标:Java 将该 json 串传入 SPL,SPL 解析 Json,合并下层订单,并进行过滤。
这里的计算步骤稍多,需要更专业的 SPL 开发和调试环境。执行 [安装目录]\esProc\bin\esproc.exe(Linux\Mac 下为 esproc.sh), 打开 SPL IDE,编辑以下脚本文件:



A

1

=json(strJson)

2

=A1.conj(Orders)

3

=A2.select(Amount>arg1 && Amount<=arg2 && like@c(Client,"*business*"))

IDE中的样子:

1png
代码中的 strJson、arg1、arg2 是参数,可以来自 Java JDBC 或报表工具。通过菜单 Program->Parameter 定义参数,如下:

2png
注意:在 SPL 代码里,Json 串是常数,可以直接使用,但在 Java 代码里,Json 串是普通字符串,传入 SPL 后需要先用 json() 函数解析再使用。为了保持代码一致,在 IDE 里测试 Json 串参数时,需要在前面加单引号,以便模拟成普通字符串。
执行或调试脚本后,依次点击 A1-A3,可以在右侧看到每一步的计算结果:

3png

4png

6png

在 Java 中调用 SPL 脚本:将上述 SPL 脚本存为文件 (比如 splFile.splx),再在 Java 中以存储过程的形式引用该文件名。

Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = connection.prepareCall("{call splFile (?,?, ?)}");
statement.setString(1,strJson);
statement.setInt(2, 1000);
statement.setInt(3, 3000);
ResultSet result= statement.executeQuery();

Json 串经常来自 HTTP 数据源(比如 Restful),而不是文件。SPL 可以直接读 HTTP 数据源,这样就不必从 Java 中传入参数了。比如:



A

1

=httpfile("http://127.0.0.1:6868/restful/emp_orders").read()

2

=json(A1)

3

=A2.conj(Orders)

4

=A3.select(Amount>1000 && Amount<=3000 && like@c(Client,"*business*"))

更详细的信息(比如访问安全性等问题)可以参考SPLHTTP/WebService/Restful 服务的访问

SPL提供了外部库接口,用来支持更多的数据源,比如从Kafka取数并计算:


A

1

=kafka_open("/kafka/my.properties", "topic1")

2

=kafka_poll(A1)

3

=A2.derive(json(value):v).new(key, v.fruit, v.weight)

4

=stax_close(A1)

还支持MongoDBbson格式:


A

1

=mongo_open("mongodb://127.0.0.1:27017/mongo")

2

=mongo_shell(A1,"test1.find()")

3

=A2.conj(Orders)

4

=A3.select(Amount>1000 && Amount<=3000 && like@c(Client,"*business*")).fetch()

5

=mongo_close(A1)

外部库需要配置好才能使用,具体用法可以参考 外部库介绍

延伸阅读资料: jsonpath xpath SPL开源 SPLWebservice/Restful 的后处理利器