在进行文本处理时,经常会遇到对大文件进行集合运算的情况,比如找出两个文件不同的行数据。用命令行的grep\cat命令处理此类问题时,写法很简单,但效率太低,用高级语言处理此类问题虽然可以获得较高的运行效率,但代码编写复杂度确相当高。
用集算器来进行大文件的集合运算和多线程并行计算,不仅代码简洁,而且性能优异。
文件file1.txt和file2.txt存储着大量的字符串,找出两者共同的行数据(交集)。部分数据如下:
两个大文件
两个文件都超出内存时,可以使用集算器的游标归并来实现交集运算,代码如下:
A1、B1:以游标的形式打开文件。函数cursor并不会将数据全部读入内存,而是以游标(流)的方式打开文件,因此不会占据内存空间。函数cursor使用了默认参数,即:以tab为列分割符读入全部的字段,自动命名为_1、_2、_3…_n。对于本案例来说,只有一个字段_1。
A2=[A1.sortx(_1),B1.sortx(_1)].merge@xi(_1)
使用归并算法找出两者共同的行数据,也就是求交集。归并算法要求数据有序,因此要先用sortx函数对游标进行排序,即A1.sortx(_1)和A2.sortx(_1),这里的_1是文件默认字段名。函数merge表示对多组数据进行归并(本案例是两组),没有参数选项时,可以对内存中的集合进行归并,使用参数选项@x表示对游标进行归并,使用参数选项@i表示归并的结果是交集。
注意,A2的运算结果仍然是游标,仍然不会占据内存空间。只有遇到export/fetch/groups等函数时,集算器引擎才会分配合适的内存缓冲区,并将前面的游标计算自动转化为内存计算。
A3=file("E:\\result.txt").export(A2)
将游标A2写入文件。函数export既支持将内存数据写入文件,也支持将游标写入文件。这里使用了默认参数,即:无列名,列分割符为Tab,覆盖文件而不是追加,写成文本文件而不是二进制。打开result.txt,可以看到部分数据如下:
值得注意的是,前面的集算器代码是分步计算,事实上可以将它们合为一句:A1=file("e:\\result.txt").export([file("E:\\file1.txt").cursor().sortx(_1),file("E:\\file2.txt").cursor().sortx(_1)].merge@xi(_1)).
另外,本案例只实现了交集,其实还有并集、合集、差集,只需要修改单元格A2中函数merge的选项即可。比如,将file1.txt和file2.txt合并,并去除两者重复的成员(并集)。求并集应当使用函数选线@u,代码是:[A1.sortx(_1),B1.sortx(_1)].merge@xu(_1),并集的结果如下:
如果不去除重复成员(和集),则代码是:[A1.sortx(_1),B1.sortx(_1)].merge@x(_1),这也是归并的本意,计算结果如下:
如果想找到在file1.txt,但不在file2.txt中的数据(差集),则应当使用函数选项@d,代码是[A1.sortx(_1),B1.sortx(_1)].merge@xd(_1),计算结果如下:
注意:差集不满足交换律,所以想获得在file2.txt,但不在file1.txt的数据时,应当使用代码[B1.sortx(_1),A1.sortx(_1)].merge@xd(_1),计算结果如下:
文件一大一小
如果只有一个文件超出内存,那就可以将小文件读入内存,再用Hash查找的方法来进行集合运算,这样可以显著提高效率。集算器代码如下:
A1:用游标的方式打开文件。
A2=file("e:\\file2.txt").import(),这句代码直接将小文件file2.txt读入内存。函数import和cursor类似,默认的字段名也是_1、_2。在IDE中点击B1可以看到当前格的计算结果:
B2>B1.primary(_1).index()
上述代码用来给B1设置主键,并建立Hash索引,这样可以大大提高查询速度。B1和B2可以合为一句:B1=file("E:\\ file2.txt").import().primary(_1).index().
A3=A1.select(B1.find(~._1))
这句代码用来查询出游标A1和B1相同的数据,即求交集。函数select用来执行查询,符合条件的数据将被取出。函数select内可以使用~来代表当前记录。
查询条件是B1.find(~._1),这表示从B1中找到A1中当前记录的_1字段。
注意,这句代码的计算结果仍然是游标。
A4=file("E:\\result.txt").export(A3),这句代码将最终计算结果写入文件。
计算差集时,可以将A3单元格中的代码改成A1.select(!B1.find(~._1)),也就是从A1中找出不在B1里的那些行数据。
计算file1和file2的并集时,可以先计算出file1和file2的差集,再和file2做合并。
A4格的表达式[A3,B1.cursor()].conj@x(),函数conj可以进行多个集合的合并(合集),比如[[1,2,3],[2,3],[]]=[1,2,3,2,3]。函数选项@x可以合并多个游标里的数据。由于B1不是游标,因此要用函数cursor将B1变换为游标,即B1.cursor(),这要比从文件里再读一遍来得快。
一大一小文件并行计算
前面的算法是串行,改成并行可以进一步提高性能,具体做法是用多个线程并行读取文件,每个线程都用游标访问文件的一部分,并同时进行集合计算,最后再将每个游标的结果合并。
在相同的硬件环境下对2.77G大文件和39.93M的小文件进行测试,串行时平均耗时85秒,并行时平均耗时47秒,性能提高接近一倍。由于集合运算的复杂度较小,瓶颈会产生在硬盘读取上,如果进一步加大运算的复杂度,性能提升的幅度将会更大。
集算器并行计算的代码如下:
B1:将小文件读入内存,设置主键并创建索引。
A2=4,A2是分段数量,即将文件分成4段。分段数量不宜过多,一般不能超过CPU的核数,否则会排队等待,而没有实质提速效果。具体的最大并行数可以在环境选项中配置。
A3=A2.(file("e:\\file1.txt").cursor@z(;, ~:A2))
上面的代码按照分段数量生成4个游标。其中A2.(express)表示按照括号内的表达式依次计算A2的成员,括号内可用“~”来表示当前成员。A2一般是集合,比如["file1", " file2"]或[2,3],A2如果是从1开始的连续数字,比如[1,2,3,4],则可以简写成4.( express),案例中的代码就是这种情况。
括号内的表达式是file("e:\\file1.txt").cursor@z(;, ~:A2),其中函数cursor使用了选项@z,这表示将文件分段,用游标取其中的某一段。~:A2,这表示文件会被大致分为4段(A2=4),“~”是A2的当前成员,因此每个游标依次对应第1、第2、第3、第4段文件。
另外,之所以是“大致分”,是因为精确分会出现半行数据的情况,而集算器会去头补位,自动取出整行数据。JAVA要实现这种处理要麻烦得多。
A4=A3.(~.select(B1.find(~._1))),这句代码针对A3中的每个游标计算交集,计算结果是游标的集合。
A5=A4.conj@xm(),将A4中的多个游标进行并行合并。
A6=file("e:\\result.txt”).export(A5),将计算结果输出到文件中。到此为止,交集已经计算完成,差集和并集的计算可以参考之前的案例。
集算器可以独立使用,也可以和JAVA集成。下面通过JDBC将集算器脚本集成在JAVA里。JAVA代码如下:
//建立esProc jdbc连接
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
//调用esProc,其中test.dfx是脚本文件名
st =(com.esproc.jdbc.InternalCStatement)con.prepareCall("call test()");
st.execute();//执行esProc存储过程,也可以传入参数并传出计算结果。
对于第一个案例中的简单脚本,可以嵌入JAVA代码中直接执行,而不必编写脚本文件(text.dfx)。相应的JAVA代码如下:
ResultSet set=st.executeQuery("file(\"e:\\result.txt\").export([file(\"E:\\file1.txt\").cursor().sortx(_1),file(\"E:\\file2.txt\").cursor().sortx(_1)].merge@xi(_1))");
相关推荐
EXCEL 对批量数据的多次重复或相似的统计和交叉性集合运算操作比较困难或效率不高 而使用 Visual Basic 开发平台利用ADO 数据库连接和操作技术可以很好的解决这样的问题 提高 EXCEL 文件数据的处理效率 这个方法前提...
使用集合初始化表达式来初始化字典 220 嵌套类型 221 部分类别和方法 222 限制 224 匿名型别 227 在查询中传回项目属性的子集 229 界面 230 明确界面实作 232 明确实作接口成员 234 使用继承明确实作接口成员 236 ...
而且它提供高传输率(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求(requirements)这样可以流的形式访问(streaming access)...
4.3 使用生成器创建新的迭代模式 4.4 实现迭代器协议 4.5 反向迭代 4.6 带有外部状态的生成器函数 4.7 迭代器切片 4.8 跳过可迭代对象的开始部分 4.9 排列组合的迭代 4.10 序列上索引值迭代 4.11 同时迭代...
史上最全韩顺平毕业班视频------这里只有9月份,8,10,11月份在另外一个文件下。 传智播客PHP就业班视频课程列表 8-11 1.html介绍 html运行原理① 8-11 2.html运行原理② html文件基本结构 html元素和属性 8-11 3....
34、多媒体技术,就是指使用计算机综合处理多种媒体信息,使多种信息建立逻辑连接 ,集成为一个系统并具有交互性得技术。 35、对网络系统而言,信息安全主要包括信息得存储安全与信息得传输安全。 36、计算机病毒...
实例057 用List集合传递学生信息 70 实例058 用TreeSet生成不重复自动排序 随机数组 71 实例059 Map映射集合实现省市级联选择框 73 第4章 字符串处理技术 75 4.1 格式化字符串 76 实例060 把数字格式化为货币字符串 ...
在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。因此常用以下程序段打开文件: if((fp=fopen("c:\\hzk16","rb")==NULL) { printf("\nerror on open c:\\hzk16 file!"); getch(); exit(1); } ...
7.2.5 在集合运算中使用INTO 7.2.6 避开不支持的逻辑阶段 7.3 总结 第8章 数据聚合和透视 8.1 OVER 子句 8.2 决胜属性(Tiebreaker) 8.3 连续聚合 8.3.1 累积聚合(Cumulative Aggregation) 8.3.2 滑动...
11.5.3 使用Soapsuds.exe分离程序集 11.5.4使用工厂方法实现分离 11.6 Remoting中的方法回调 11.6.1远程回调方式说明 11.6.2客户端类型和服务端类型 …… 第12章 在.NET中操作XML 第13章 .NET应用程序配置 ...
史上最全韩顺平毕业班视频------这里只有10月份,8,9,11月份在另外一个文件下。 传智播客PHP就业班视频课程列表 8-11 1.html介绍 html运行原理① 8-11 2.html运行原理② html文件基本结构 html元素和属性 8-11 3....
34、多媒体技术,是指使用计算机综合处理多种媒体信息,使多种信息建立逻辑连接, 集成为一个系统并具有交互性的技术。 35、对网络系统而言,信息安全主要包括信息的存储安全和信息的传输安全。 36、计算机病毒一般...
14、 多媒体 技术是指,使用计算机综合处理多种媒体信息,使多种信息建立逻辑连接,集成为 一个系统并具有交互性的技术。 15、 对网络系统而言,信息安全主要包括信息的存储安全和信息的 传输安全。 16、 计算机...
A、文件占用的空间变大 B、发生异常蜂鸣声 C、屏幕显示异常图形 D、机内的电扇不转 2. Windows98支持下面___C__网络协议。 A、Net BEUI B、IPX/SPX C、TCP/IP D、Banyan VINES 3.为了方便人们记忆;阅读和编程,...
作为基于分布式文件存储的数据库,在目前的云计算实践中,MongoDB炙手可热。《深入云计算(MongoDB管理与开发实战详解)》系统全面的介绍了MongoDB开发、管理、维护和性能优化等方方面面。详细而深入,对MongoDB的开发...