WEB 上的计算引擎

Web 上的数据接口以 restful 和 WebService 为主,格式通常是多层的 Json 和 XML。多层数据可承载更通用更丰富的信息,但结构上比传统的二维数据复杂,计算难度也更大。可用于 Web 计算的工具或引擎表面上不少,但都有各自的缺点,JsonPath/XPath 等类库解析能力强,但计算能力不足;Python Pandas 计算能力较强,但难以被 Java 集成,而且数据对象 DataFrame 不是专为多层数据设计的,遇到复杂计算时代码也难写;Scala Spark 在集成性方面好一些,但架构沉重,学习难度也大。

Web上的计算引擎,还有一个更好的选择:esProc SPL。

esProc SPL 是基于 JVM 的开源程序语言,内置专业的多层数据对象,提供了方便的 Web 解析 / 生成函数,可简化复杂的多层数据计算,容易被 Java 应用集成。

专业的多层数据对象

SPL 内置专业的多层数据对象序表,适合承载 Web 数据格式,擅长表达复杂的层级关系。

例如,对 Json 串进行条件查询,并用 Json 串返回计算结果:


A

B

1

=json(p_JsonStr)

Json 串解析为 SPL 序表

2

=A1.conj(Orders)

合并下层记录

3

=A2.select(Amount>1000 && Amount<=2000)

条件查询

4

=json(A3)

结果转为 Json 串

A1:外部参数 p_JsonStr 是 Json 串,函数 json 将其转为序表(SPL 的结构化数据对象)。在 SPL IDE 中点击 A1 格可以看到序表的多层结构,其中,EId、State 等字段存储简单数据类型,Orders 字段存储记录集合(二维表)。点击 Orders 中的某一行,可以展开观察数据:

1png

A2、A3:对序表进行计算,计算结果同样是序表。

A4:函数 json 既可以将 Json 串转为序表,也可以将序表转为 Json 串。

SPL 提供了自由的多层数据访问方法,可以通过点号访问不同的层级,通过下标访问不同的位置。

第1层的单个字段的集合:A1.(Client)
第1层的多个字段的集合:A1.(\[Client,Name\])
第1层第10条记录:A1(10)
第1层第10条记录的Orders字段(即所有下层记录):A1(10).Orders
第1层第10条件记录Orders字段的单个字段的集合:(A1(10).Orders).(Amount)
第1层第10条件记录Orders字段的第5条记录:(A1(10).Orders)(5)
第1层的第10-20条记录:A1(to(10,20))
第1层的最后三条记录:A1.m(\[-1,-2,-3\])

序表是与字符串格式无关的高级数据对象,不仅可以解析 Json 串,也可以解析 XML 串,且计算代码通用。例如,p_XMLStr 是多层的 XML 串(与前面的 Json 同构),进行同样的条件查询时,只要修改 A1:=xml(p_XMLStr,"xml/row")

与函数 json 类似,函数 xml 也支持双向转换。

SPL 提供了各类 Web 数据接口,可以方便地访问 restful 或 WebService,并解析为统一的序表。比如访问 restful 接口,只要将前面例子的 A1 改为:


A

1

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


=json(A1)

函数 httpfile 用于访问 url 网址,可指定端口、Header、字符集、IPV4/V6、Post/Get,支持 Cookie 或令牌的鉴权方式。

访问 WebService 接口:


A

1

=ws_client("http://127.0.0.1:6868/ws/RQWebService.asmx?wsdl")

2

=ws_call(A1,"RQWebService":"RQWebServiceSoap":"getEmp_orders")

函数 ws_client 建立 WebService 客户端,函数 ws_call 查询 WebService 服务。

由于序表与字符串格式、数据源无关,所以没有特别说明时,下面例子都通用于 Json\XML\ 参数串 \Web。不难想象,SPL 还可以解析本地 Json 文件或 XML 文件,二维数据可以看作多层数据的简化情况,所以序表还可以解析并计算 csv 文件或数据库表(不是本文重点)。

强大的计算能力

对于解析后的序表,SPL 提供了丰富计算函数,可以轻松完成日常的 SQL 式计算。


A

B

1

….

生成多层序表

2

=A1.conj(Orders)

合并下层记录

3

=A2.groups(State,Gender;avg(Salary),count(1))

多字段分组汇总

4

=A1.new(Name,Gender,Dept,Orders.OrderID,Orders.Client,Orders.Client,Orders.SellerId,Orders.Amount,Orders.OrderDate)

关联

5

=A1.sort(Salary)

排序

6

=A1.id(State)

去重

7

=A2.top(-3;Amount)

topN

8

=A2.groups(Client;top(3,Amount))

组内TopN(窗口函数)


SPL 还提供了符合 SQL92 标准的语法,支持集合计算、case when、with、嵌套子查询等。

SPL 表达能力强,适合计算结构复杂的多层数据。比如:restful 返回多层 Json,包含多个子文档,结构较复杂,部分数据如下:

[
   {
      "race": {
          "raceId":"1.33.1141109.2",
          "meetingId":"1.33.1141109"
      },
      ...
      "numberOfRunners": 2,
      "runners": [
        {     "horseId":"1.00387464",
              "trainer": {
                  "trainerId":"1.00034060"
              },
          "ownerColours":"Maroon,pink,dark blue."
          },
          {   "horseId":"1.00373620",
              "trainer": {
                  "trainerId":"1.00010997"
              },
          "ownerColours":"Black,Maroon,green,pink."
          }
      ]
   },
...
]

现在要对不同的层级进行分组汇总(对 trainerId 分组,统计每组中 ownerColours 的成员个数),直接在 Java 用使用一般的类型仍很复杂,SPL 就简单多了:


A

1

2

=A1(1).runners

3

=A2.groups(trainer.trainerId; ownerColours.array().count():times)

SPL 支持分步计算、有序计算、分组后计算等逻辑较复杂的计算,很多 SQL/ 存储过程难以实现的计算,用 SPL 解决起来就很轻松。比如,找出销售额累计占到一半的前 n 个大客户,并按销售额从大到小排序:


A

B

1

/取数据

2

=A1.sort(amount:-1)

/销售额逆序排序

3

=A2.cumulate(amount)

/计算累计序列

4

=A3.m(-1)/2

/最后的累计即总额

5

=A3.pselect(~>=A4)

/超过一半的位置

6

=A2(to(A5))

/按位置取值

SPL 有丰富的日期和字符串函数,能有效简化相关计算。

季度增减:elapse@q("2020-02-27",-3) // 返回 2019-05-27

N 个工作日之后的日期:workday(date("2022-01-01"),25) // 返回 2022-02-04

字符串类函数,判断是否全为数字:isdigit("12345") // 返回 true

取子串前面的字符串:substr@l("abCDcdef","cd") // 返回 abCD

按竖线拆成字符串数组:"aa|bb|cc".split("|") // 返回 ["aa","bb","cc"]

SPL 还支持年份增减、求季度、按正则表达式拆分字符串、拆出单词、按标记拆 HTML 等大量函数。

值得一提的是,为了进一步提高开发效率,SPL 还创造了独特的函数语法。比如用选项区分类似的函数,只过滤出符合条件的第 1 条记录,可使用选项 @1:

T.select@1(Amount>1000)

从后往前查找第 1 条记录,可以使用 @z:

T.select@z1(Amount>1000)

热部署集成架构

SPL 提供了 JDBC 接口,可以被 Java 代码方便地集成。简单的 SPL 代码可以像 SQL 一样,直接嵌入 JAVA:

String jsonStr=…   //Json串
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String query="=json(json($["+jsonStr+"]).conj(Orders).select((Amount>1000 && Amount<=2000)))";
ResultSet result = statement.executeQuery(query);

复杂的 SPL 代码可以先存为脚本文件,再以存储过程的形式被 JAVA 调用,可有效降低计算代码和前端应用的耦合性。

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call getRestful(?, ?)}");
statement.setObject(1, "2020-01-01");
statement.setObject(2, "2020-01-31");
statement.execute();

SPL 是解释型语言,外置的代码无须编译就能执行,支持不停机热部署,适合变化的业务逻辑,运维复杂度低。


以下是广告时间

对润乾产品感兴趣的小伙伴,一定要知道软件还能这样卖哟性价比还不过瘾? 欢迎加入好多乾计划。
这里可以低价购买软件产品,让已经亲民的价格更加便宜!
这里可以销售产品获取佣金,赚满钱包成为土豪不再是梦!
这里还可以推荐分享抢红包,每次都是好几块钱的巨款哟!
来吧,现在就加入,拿起手机扫码,开始乾包之旅



嗯,还不太了解好多乾?
猛戳这里
玩转好多乾