Java 程序员如何轻松搞定文本计算?

 

解决办法:esProc - Java 专业计算包

imagepng

esProc 是专门用于 Java 计算的类库,旨在简化 Java 代码,提供不依赖数据库的计算能力。 SPL 是基于 esProc 计算包的脚本语言,和 Java 程序一起部署,用法和 Java 程序中调用存储过程相同,通过 JDBC 接口调用,返回 ResultSet 对象。

常规文本查询

Java 只提供比较基础的底层函数,缺乏专业的结构化数据计算函数,比如数据集的过滤、排序、分组统计、连接等,都需要程序员自己去编写,用 SPL 读取则非常简单。

比如:找出英语平均分低于70分的班级。


A

1

=T(“E:/txt/Students_scores.txt”)

2

=A1.groups(CLASS;avg(English):avg_En)

3

=A2.select(avg_En<70)

这段代码可在esProcIDE中调试/执行,然后将其存为脚本文件(比如condition.dfx),通过JDBC接口在JAVA中调用,具体代码如下:

  package Test;
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.ResultSet;
  import java.sql.Statement;
  public class test1 {
      public static void main(String[]   args)throws Exception {
          Class.forName("com.esproc.jdbc.InternalDriver");
          Connection connection   =DriverManager.getConnection("jdbc:esproc:local://");
          Statement statement =   connection.createStatement();
          ResultSet result =   statement.executeQuery("call condition.dfx");
          printResult(result);
          if(connection != null)   connection.close();
      }

…

}

上面的用法类似存储过程,其实 SPL 也支持类似 SQL 的用法,即无须脚本文件,直接将 SPL 嵌入 JAVA,代码如下:

…
ResultSet result = statement.executeQuery("
=file(\"D:\\sOrder.csv\").groups(CLASS;avg(English):avg_En).select(avg_En<70)");
…


用 SPL 实现多文本关联计算:

比如:销售订单信息和产品信息分别存储在两个文本文件中,计算各订单的销售额。两个文件数据结构如下图:

..


A

1

=T(“e:/orders/sales.csv”)

2

=T(“e:/orders/product.csv”).keys(ID)

3

=A1.join(ProductID,A2,Name,Price)

4

=A3.derive(Quantity*Price:amount)


一个目录里有很多相同结构的文本,用 SPL 合并后查询汇总同样十分简单:


A
1 =directory@p("./"+user+"/*.csv")
2 =A1.conj(file(~).import@tc())
3 =A2.groups('Customer ID':CID,year('Purchase Date'):Year; 'Customer   Name':Customer,sum('Sale Amount'):Total,round(avg('Sale Amount'),1):Average)
4 =A3.select(Year==when).new(Customer,Total,Average)


SPL 中提供了完善的用 SQL 查询文件数据的方法:

比如:州信息,部门信息和员工信息分别存储在3个文本文件中,查询经理在California州的New York州员工。


A

1

$select   e.NAME as ENAME
from   E:/txt/EMPLOYEE.txt  as e
     join E:/txt/DEPARTMENT.txt as d on   e.DEPT=d.NAME
     join E:/txt/EMPLOYEE.txt  as emp on d.MANAGER=emp.EID
where   e.STATE='New York' and emp.STATE='California'


大文本计算

如果数据量较大,SPL 还有游标读取的方式,可以在游标上绑定计算,比如按 Employees 表的 Dept 字段分组,对 Orders 表的 Amount 字段汇总,在游标上实现了排序、关联和分组计算,可以利用小内存完成大数据计算。


A

1

=file("E:/txt/Employees.txt").cursor@t().sortx(EId)

2

=file("E:/txt/Orders.txt").cursor@t().sortx(SellerId)

3

=joinx(A2:O,SellerId; A1:E,EId)

4

=A3.groups(E.Dept;sum(O.Amount))

大文本计算经常需要加入并行计算提高计算效率,每个线程各自用大文件计算的方式处理一段数据,最后将各线程处理的结果进行汇总。

比如:在大数据用户登录记录文件 user_info_reg.csv 中,统计各省用户的登录总次数,SPL 脚本如下:

A
1 =file(“E:/txt/user_info_reg.csv”).cursor@tcm(;4)
2 =A1.groups(id_province;count(~):cnt)

在 SPL 中使用并行提速非常容易,@m 表示并行计算,参数 4 表示 4 路并行,与单线程代码相比,仅仅多一个游标选项与参数,让用户使用并行非常方便。


不规则文本处理

如下数据格式,要求每行从开始都有的字段各分一列,其他不够有多少项归为一列。

col1,col2,clo3,col4
word1,date1,date2,port1,port2,....some amount of port
word2,date3,date4,
....

SPL 处理如下:

A
1 =file(“file.txt”).import@st()
2 =A1.(#1.split@c()).new(~(1):col1,~(2):col2,~(3):col3,~.to(4,).concat@c():col4)

导入文本,按逗号分隔,第 1-3 项各分一列,从第 4 项开始分为一列。

又比如,文本 T2.txt 中都是形如下行的串,需要提取含有字符 US 前的州名(LA)和 COOP: 后的数字。

COOP:166657,'New Iberia Airport Acadiana Regional LA US',200001,177,553
COOP:177562,'Bobo Dioulasso Airport BF',200001,322,682
COOP:179534,'La Tapoa Airport NE',200002,408,514
COOP:196410,'Caribou Municipal Airport ME US',200003,436,658
……
A
1 =file(“T2.txt”).import@c()
2 =A1.select(pos(_2, “US”)!=null)
3 =A2.derive(mid(_2, pos(_2,"US")-2, 2):State)
4 =A3.derive(right(_1, pos(_1,“:”)+1):ID)

导入文本,过滤第二列,字符串必须含有”US”; 找到” US”的位置,左挪 2 个位置,向右提取 2 个字符; 找到”:”的位置,向右提取到末尾,提取结果如下:

imagepng

集算器也提供了对正则表达式,但仍建议用常规方法实现,集算器 IDE 支持单步、断点等高级调试模式,应对复杂的拆解需求非常便利。

更多计算示例

参见 SPL 应用计算之文件计算