条件查询大文本文件的通用办法

在进行文本处理时,经常会遇到对大文件进行条件查询的情况。用命令行的grep\cat可以处理一些简单情况,写法很简单,但效率太低,用高级语言处理此类问题虽然可以获得较高的运行效率,但代码编写复杂度却相当高。如果遇到条件比较复杂或条件经常变化的情况,还需要额外实现一套类SQL的底层库函数,其难度会更大。

集算器支持大文件条件查询和多线程并行计算,代码简洁性能优异,下面通过例子来看一下具体作法。

文本文件employee.txt中保存了员工数据。现在要读取员工信息,从中找出198111日(含)之后出生的女员工,最后将查询结果输出到result.txt中。

         文本文件empolyee.txt的格式如下:

EID   NAME       SURNAME        GENDER  STATE        BIRTHDAY        HIREDATE         DEPT         SALARY

1       Rebecca   Moore      F       California 1974-11-20       2005-03-11       R&D          7000

2       Ashley      Wilson      F       New York 1980-07-19       2008-03-16       Finance    11000

3       Rachel      Johnson   F       New Mexico     1970-12-17       2010-12-01       Sales         9000

4       Emily         Smith        F       Texas        1985-03-07       2006-08-15       HR    7000

5       Ashley      Smith        F       Texas        1975-05-13       2004-07-30       R&D          16000

 

集算器代码:



    
A1:以游标的形式打开文件。函数cursor并不会将数据全部读入内存,而是以游标(流)的方式打开文件,因此不会占据内存空间。函数cursor使用了默认参数,即:以tab为列分割符读入全部的字段。选项@t表示文件的第一行是列名,之后可以使用直观的列名来书写表达式,如果没有这个选项,则会自动命名为_1_2_3…_n

A2=A1.select(${where})

按照条件过滤。这里使用宏来实现动态解析表达式,其中的where就是动态传入的参数,需要提前定义。定义参数的界面如下:



 

集算器会先计算${…}里的表达式,将计算结果作为宏字符串值替换${…}之后解释执行。比如按照案例中的条件给where赋值为BIRTHDAY>=date(1981,1,1) && GENDER=="F",则A2的表达式会被替换为=A1.select(BIRTHDAY>=date(1981,1,1) && GENDER=="F")。参数可以在IDE中输入,也可以来自JAVA代码和命令行。

A3=file("D:/result.txt").export@t(A2)将计算结果输出到文件中。如果计算结果总是很小,也可以用=A2.fetch()将计算结果放入内存并直接观察,或者用result A2.fetch()将计算结果返回给JAVA程序。

本案例的最终结果如下:



 
         本案例实现的是动态查询,即过滤条件发生变化时不用改变代码,只需改变where参数即可。例如,条件变为:查询198111日(含)之后出生的女员工,或者NAME+SURNAME等于”RebeccaMoore”的员工。Where的参数值可以写为:BIRTHDAY>=date(1981,1,1) && GENDER=="F" || NAME+SURNAME=="RebeccaMoore"。执行之后,A2中的结果集如下图:



 
前面的算法是串行,改成并行可以进一步提高性能,具体做法是用多个线程并行读取文件,每个线程都用游标访问文件的一部分,并同时进行条件查询,最后再将每个游标的结果合并。

集算器并行计算的代码如下:



     
A1=4A1是分段数量,即将文件分成4段。分段数量,也就是实际执行时的并行数,一般不要超过CPU的核数,否则会形成排队等待,并不能提高性能。实际使用最大并行数量可以在选项中配置。

A2=A1.(file("d:/employee.txt").cursor@z(;, ~:A1))

上面的代码按照分段数量生成4个游标。其中A1.(express)表示按照括号内的表达式依次计算A1的成员,括号内可用“~”来表示当前成员。A1一般是集合,比如["file1", " file2"][2,3]A1如果是从1开始的连续数字,比如[1,2,3,4],则可以简写成4.( express),案例中的代码就是这种情况。

括号内的表达式是file("d:/employee.txt ").cursor@z(;, ~:A1),其中函数cursor使用了选项@z,这表示将文件分段,用游标取其中的某一段。~:A1表示文件会被大致分为4(A1=4),当前取第~段。“~”是A1的当前成员,因此每个游标依次对应第1、第2、第3、第4段文件。

另外,之所以是“大致分”,是因为精确分会出现半行数据的情况,而集算器会去头补位,自动取出整行数据。

A3=A2.(~.select(${where}))这句代码针对A2中的每个游标(即~)进行计算,求查询出游标中符合条件的行数据。这里的计算结果仍然是四个游标。

A4=A3.conj@xm()这句代码将A3中的多个游标进行并行合并。

A5=file("d:/result.txt”).export(A4),将最终计算结果输出到文件中。      

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值