集算器協(xié)助java處理結(jié)構(gòu)化文本的集合運算
JAVA不直接支持集合運算,因此要用嵌套循環(huán)才能實現(xiàn)文本文件之間的交集、并集、差集 等集合運算,如果文件數(shù)量較多,或者文件較大而無法放入內(nèi)存直接計算,再或者要按照多個字段進行集合運算,則相應(yīng)的代碼會更加復(fù)雜。集算器直接支持集合運 算,可以協(xié)助JAVA輕松實現(xiàn)此類算法,下面我們通過例子來看一下具體作法。
有兩個小文件:f1.txt和f2.txt,***行是列名,現(xiàn)在需要對文件中的Name字段進行交集運算。部分數(shù)據(jù)如下:
文件f1.txt:
文件f2.txt:
集算器代碼:
A1、B1:用import函數(shù)將文件讀=[A1.(Name),B1.(Name)].isect()入內(nèi)存,默認的分隔符是tab。這里的函數(shù) 選項@t表示將***行讀為列名,這樣一來后續(xù)的計算就可以直接用Name和Dept來引用相應(yīng)的列,如果***行不是列名,則應(yīng)當(dāng)用_1和_2這種默認列名 來引用。
計算后A1和B1的值分別如下:
函數(shù)import可以讀取指定的列,比如本案例只有Name會參與計算,因此可以只讀取Name列,對應(yīng)的代碼是:file(“E:\\f1.txt”).import@t(Name) 。
A2= 函數(shù)isect可以進行集合間的交集運算,A1.(Name)表示取出A1的Name列,形成一個集合,B1.(Name)表示取出B1的Name列。本案例的最終結(jié)果如下:
A3:result A2。這表示將計算結(jié)果輸出到JDBC接口。A3可以和A2合為一步:result [A1.(Name),B1.(Name)].isect() 。
上述是求交集的過程,求并集只需換個函數(shù):[A1.(Name),B1.(Name)].union(),計算結(jié)果如下:
求差集的代碼:[A1.(Name),B1.(Name)].diff(),計算結(jié)果如下:
還有一類特殊的集合算法:和集,即求并集時保留重復(fù)的元素,和集的代碼:[A1.(Name),B1.(Name)].conj(),計算結(jié)果如下:
可以直接用運算符來代替函數(shù),寫法更加簡潔,比如交集,并集、差集、合集可以改寫為:
A1.(Name) ^ B1.(Name)
A1.(Name) & B1.(Name)
A1.(Name) \ B1.(Name)
A1.(Name) | B1.(Name)
也可以對多個文件進行集合運算,比如f1.txt、f2.txt、f3.txt讀入內(nèi)存后對應(yīng)的變量分別是A1、B1、C1,對它們求交集,代碼如 下:A1.(Name) ^ B1.(Name) ^C1.(Name) 或 [A1.(Name),B1.(Name),C1.(Name)].isect() 。
有時候文件比較大,會影響集合運算的性能,可以用sort函數(shù)事先排序,再用merge函數(shù)來進行集合運算,這樣一來性能會顯著提高。其中,求交集時應(yīng)當(dāng)使用函數(shù)選項@i,并集使用@u,差集使用@d,對應(yīng)的代碼分別如下:
=[A1.(Name).sort(),B1.(Name).sort()].merge@i()
=[A1.(Name).sort(),B1.(Name).sort()].merge@u()
=[A1.(Name).sort(),B1.(Name).sort()].merge@d()
函數(shù)merge還可以進行多字段的集合運算,假設(shè)不同的Dept會存在相同的Name,現(xiàn)在需要將Dept和Name當(dāng)作一個整體來進行交集運算, 對應(yīng)的代碼如下:[A1.sort(Dept,Name),B1.sort(Dept,Name)].merge@i(Dept,Name) 。
計算結(jié)果如下:
對于內(nèi)存放不下的大文件,可以用cursor函數(shù)來讀取文件,并用merge函數(shù)來實現(xiàn)集合運算。其中,求交集的代碼如下:
A1=file(“e:\\f1.txt”).cursor()
B1=file(“e:\\f2.txt”).cursor()
A2=[ A1.sortx(Name),B1.sortx(Name)].merge@xi(Name)
注意,這里函數(shù)cursor并不會將數(shù)據(jù)全部讀入內(nèi)存,而是以游標(或流)的方式打開文件。集算器引擎會自動分配合適的緩沖區(qū),每次讀取一部分數(shù)據(jù)參與計算,再循環(huán)往復(fù),完成最終的計算。
與內(nèi)存計算不同,操作游標需要使用游標函數(shù),比如排序時應(yīng)當(dāng)使用函數(shù)sortx。這里的merge函數(shù)使用了兩個函數(shù)選項,@i表示求交集,@x表示參與計算的對象不是內(nèi)存數(shù)據(jù),而是游標。另外,union等函數(shù)只能進行內(nèi)存數(shù)據(jù)的集合運算,不能用于大文件。
上述腳本已經(jīng)完成了所有的數(shù)據(jù)處理工作,接下來通過JDBC將集算器腳本集成在JAVA里。JAVA代碼如下:
- //建立esProc jdbc連接
- Class.forName(“com.esproc.jdbc.InternalDriver”);
- con= DriverManager.getConnection(“jdbc:esproc:local://”);
- //調(diào)用esProc,其中test是腳本文件名
- st =(com.esproc.jdbc.InternalCStatement)con.prepareCall(“call test()”);
- st.execute();//執(zhí)行esProc存儲過程
- ResultSet set = st.getResultSet();//獲得計算結(jié)果