二進制串模糊搜索的Java實現

   這個問題其實是從之前博客http://blog.csdn.net/lgnlgn/archive/2010/11/14/6008498.aspx)介紹的爬蟲去重的論文中的一個內容,問題是這樣描述的:給定Nf位的指紋集合C,對一個輸入指紋f’,如何找出C中與f’漢明距離小於k的所有指紋?

具體地,論文裏N=80億,f=64K=3

 

64位取3的漢明距離可能性一共有C(64,3)  > 40000,也得進行超過40000次的查詢如果是有序數組,採用二分搜索或者內插搜索,總量很大時每次查詢也需要幾十次計算。

 

另外一種辦法就是把64位中61位看成不變的,預先排序,這就需要排C(64,61)>40000塊,查詢的時候把f’拆成40000個可能並行地在這些塊上進行搜索。

 

無論哪種方案都是時間空間承受不了的,因此論文裏提出了個折中方案:預先排序多塊,每塊進行少量搜索。下面介紹兩種方案

 

1.假設64爲可以分成ABCD16位的4部分,16位一共可以表示2^16種可能,如果集合裏有100萬個指紋,也就是2^20個;假設我們按A部分排序,那麼平均地看每個指紋A部分相同的應該有2^(20-16)個。如果我們保證其中一個部分精確匹配16位,那麼漢明距離變化的3位最壞的可能性讓它發生在BCD部分,我們只需要逐一比較2^(20-16)個指紋。

例如B出現1位,C出現兩位;或者BCD各出現一個不同位。如果A出現了1位不同,B出現2位不同,那麼精確匹配C部分的16位,逐一比較C部分相同的2^(20-16)個指紋,就行了。所有的可能性都能覆蓋到。那麼集合需要4份不同的排序結果,按ABCD

 

2.如果64位分成5部分每部分分別12-13位,最壞可能要把漢明距離限制在3塊之中,一共有C(5,3)=10種可能,那麼前2塊能表示2^(25~26)個可能,10(2^30)個指紋,精確匹配前2塊以後平均只需要逐一比較2^(4~5)個。若是上一種方案,還需要平均比較2^14個呢。這種方案需要10種不同的排序。

 

  方案其實還有,這裏就不說了,下面來說下實現的考慮

一次完整的查詢是對f’在不同的排序塊中搜索以後再合併。64位就是一個8字節整數,假設有1億個指紋,就是800M,不論哪種方案,放內存都不合適,要放到外存。

Java裏隨機訪問文件可以用RandomAccessFile,後來發現用NIO裏的fileChannel效率更高。

並行搜索再合併,可以開多個線程來搜索;考慮到每次搜索的時間長短不同,同時進行100次查詢,需要開1000個線程,比較浪費,想到javaconcurrency中的線程池更適合這樣的場景。

 

實現方案1的時候,可以採用一些技巧來節省計算開銷,例如16位一共有65536種可能,在內存中維護一個65536大小的long數組array,數組的下標表示16位比特的值,數組的值表示16位比特值代表的前綴在集合中起止偏移量,例如array[0]=3表示00000000000000000號偏移開始3爲止。array需要提前計算好,array只佔64K * 8 = 512k大小,4塊加起來也只有2M。查詢f’的時候,先取出f’4個前綴16位,在數據中直接取出文件位移,再到文件中按偏移起止直接取出每個指紋後面的48bits

 

其實如果指紋總量不大,比如100萬,完全可以在放在內存中,需要320M,如果出去前16bit,只需要240M,當達到千萬級的時候才需要放到外存。當達到億級的時候,方案1每次查詢需要逐一比較漢明距離的次數達到一萬次以上,如果採用方案2,則逐一比較量降到幾百,但是總空間需要8G,如果總量達到百億,可能還得用複製更多塊的方案。

 

   我分別實現了niostreamRandomAccess方法(後倆必須算好起止直接跳過),很直接的實現;測試的時候出現不能理解的問題,在千萬級的數據集上,nio的一次查詢時間要麼0.4要麼10多ms甚至有過50ms

如果每次查詢一樣的數,速度會很快,而要是隨機的,就會很慢。但是這一批隨機數在同個進程再跑一遍的時候,缺又是和查詢一樣的數時候一樣快。百思不得其解。

 

有高手說這是文件系統緩存的問題,首次讀是冷啓動,第二次讀是熱啓動。如果是這樣瓶頸可能出在跳偏移的地方或者逐個讀取long的地方,還沒測過哪個嚴重些,如果實後者,那必須減少逐個讀取的個數,也就是必須增加複製塊數。

 

感覺是這個模糊查詢效率不高,從文件讀取出的數據並不多,就這麼慢了...而且多線程的情況下併發吞度量並沒有明顯提高。也許是本人程序水平,代碼不多,希望有高手能指點一下


代碼放這裏了:http://download.csdn.net/source/3339688

 

發佈了36 篇原創文章 · 獲贊 27 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章