SPL 实践:解析并过滤来自 RESTful 的多层 JSON

实践背景

通过 RESTful 交换数据很方便,但接收数据后如何继续计算会有点麻烦。SPL 提供了 HTTP 接口,可以直接读取 RESTful 的数据后进行计算。
如下例,电商业务中订单数据的访问被封装成 REST 接口供其他业务访问。
访问地址:
http://111.198.29.168:8503/getOrdershttp://111.198.29.168:8503/getOrders/bDate/eDate
其中:bDate 与 eDate 为路径参数,直接在 URL 中拼接即可,参数代表查询的起始和结束日期。
接口返回的 JSON 格式数据如下:

[
  {
    "order_id": "AMZ123001",
    "order_date": "2023-11-11 18:00:17",
    "order_status": "processing",
    "user_info": {
      "user_id": "USR001",
      "username": "john_doe",
      "email": "john_doe@example.com",
      "country": "USA",
      "city": "New York"
    },
    "payment_info": {
      "payment_method": "credit_card",
      "total_amount": 0
    },
    "order_details": [
      {
        "product_id": "PD001",
        "product_name": "Smartphone",
        "price": 599.99,
        "quantity": 1
      },
      {
        "product_id": "PD002",
        "product_name": "Laptop",
        "price": 1299.99,
        "quantity": 1
      }
    ]
  },

…
]

现在分析 2023 年的订单,从所有未取消的订单中找出本年购买金额最多的前 5 名客户,以便为其发放礼品奖励。

实践过程

编辑脚本

打开 SPL IDE 编写脚本:


A

1

=httpfile("http://111.198.29.168:8503/login4get?nameOrEmail=tom&userPassword="+md5("mypass")+"rememberLogin=true“:"UTF-8" ).read()

2

=A1.property("Set-Cookie")

3

=httpfile("http://111.198.29.168:8503/getOrders"+"/"+bDate+"/"+eDate:"UTF-8";"Cookie":A2).read()

4

=json(A3)

5

=A4.select(order_status!="canceled")

6

=A5.groups(user_info.user_id;sum(order_details.price*order_details.quantity):amt)

7

=A6.top(-5;amt)

8

return json(A7)

A1-A2:RESTful 访问鉴权
A3:访问数据接口,根据起止日期获取本年订单数据,其中 bDate、eDate 为脚本参数

A4:结构化 JSON 串,转换为多层序表

User_info 的下一层:

A5:过滤数据,返回所有未取消订单
A6:按照用户分组汇总订单金额。这里通过 user_info.user_id 的方式访问多层序表中各个层次的数据(有了多层序表就能天然适应 JSON 的多层结构)

A7:获得金额最大的前 5 名用户(包括用户名和金额)

A8:结果以 JSON 格式返回

Java 调用

参考 Java 如何调用 SPL 脚本 ,将 esproc-bin-xxxx.jar 和 icu4j-60.3.jar,以及配置文件 raqsoftConfig.xml 引入到项目后,通过 JDBC 调用 SPL 脚本或执行 SPL 语句。

像调用存储过程一样执行 SPL 脚本文件:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn= DriverManager.getConnection("jdbc:esproc:local://");
PreparedStatement st = conn.prepareCall("call restJsonParse (?,?)");
st.setObject(1, "2023-01-01");
st.setObject(2, "2023-12-31");
st.execute();
ResultSet rs = st.getResultSet();

或者直接执行 SPL 语句,将 IDE 中的脚本选中并复制粘贴到 Java 字符串中,就可以得到这样的串:

String spl = "==httpfile(\"http://111.198.29.168:8503/login4get?nameOrEmail=tom&userPassword=\"+md5(\"mypass\")+\"rememberLogin=true“:\"UTF-8\" ).read()\n" +
        "=A1.property(\"Set-Cookie\")\n" +
        "=httpfile(\"http://111.198.29.168:8503/getOrders\"+\"/\"+bDate+\"/\"+eDate:\"UTF-8\";\"Cookie\":A2).read() \n" +
        "=json(A3)\n" +
        "=A4.select(order_status!=\"canceled\")\n" +
        "=A5.groups(user_info.user_id;sum(order_details.price*order_details.quantity):amt)\n" +
        "=A6.top(-5;amt)\n" +
        "return json(A7)";

需要注意的是,脚本串要以双等(==)号开头。

下面执行脚本:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn= DriverManager.getConnection("jdbc:esproc:local://");
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(spl);

输出结果集得到如下 JSON 串:

[{"user_id":"USR001","amt":2399.96},{"user_id":"USR008","amt":1079.8799999999999},{"user_id":"USR005","amt":999.96},{"user_id":"USR010","amt":879.92},{"user_id":"USR007","amt":799.96}]

这样就完成了 RESTful 解析和计算,计算结果可以直接返回或传递给其他程序继续使用。

附件:
orders.json
restJsonParse.splx
RestfulJsonParse.java