我這裡介紹乙個極適合大量url快速排重的方法 ,這個演算法被稱為bloom filter,基本上,它也只適合這樣的場合。
這裡的大量是指有5000萬至1億的url,更大的資料量可能也不合適了。
所以,把目標鎖定在單機排重,一開始,試驗了perl中的hash,非常簡單的**
usedb_file;
my%db
;#tie %db, 'db_file', "createdb.dat", or die "can't initialize db:: $! ";
while
(<>
) =1;
#add code here
}#untie %db;
從標準輸入或檔案中每行乙個url讀入,插入到perl內建的hash表中,這就成了,需要輸出結果則預先判斷一下插入的key是否存在。
這個方法速度很快,可惜的是,它占用記憶體太大,假設1個url平均50位元組,5000萬個url需要2.5g記憶體。
於是又想到乙個方法,把部分資料放入硬碟空間,perl中也提供乙個現成的模組db_file,把上面**中的注釋去掉,就可使用db_file了,用法與hash一樣,只是內部用資料庫實現的。
測試了一下,速度明顯下降了乙個檔次,僅40萬的資料就要1分鐘,關鍵還在於隨著資料量的增加,速度下降加快,兩者不呈線性關係。
資料量大的時候,有可能用mysql的效能會比db_file好,但是總體上應該是一丘之貉,我已經不抱期望了。
也許db_file可以優化一下,使用更多的記憶體和少量的硬碟空間,不過這個方案還是太複雜,留給專家解決吧,一般來說,我認為簡單的方法才有可能做到高效。
下面我們的重點物件隆重登場:bloom filter。簡單的說是這樣一種方法:在記憶體中開闢一塊區域,對其中所有位置0,然後對資料做10種不同的hash,每個hash值對記憶體bit數求模,求模得到的數在記憶體對應的位上置1。置位之前會先判斷是否已經置位,每次插入乙個url,只有當全部10個位都已經置1了才認為是重複的。
如果對上面這段話不太理解,可以換個簡單的比喻:有10個桶,乙個桶只能容納1個球,每次往這些桶中扔兩個球,如果兩個桶都已經有球,才認為是重複,問問為了不重複總共能扔多少次球?
10次,是這個答案吧?每次扔1個球的話,也是10次。表面上看一次扔幾個球沒有區別,事實上一次兩個球的情況下,重複概率比一次乙個球要低。bloom filter演算法正式借助這一點,僅僅用少量的空間就可以進行大量url的排重,並且使誤判率極低。
有人宣稱為每個url分配兩個位元組就可以達到0衝突,我比較保守,為每個url分配了4個位元組,對於5000萬的數量級,它只占用了100多m的空間,並且排重速度超快,一遍下來不到兩分鐘,極大得滿足了我的慾望。
快速URL排重的方法 一
我這裡介紹乙個極適合大量url快速排重的方法,這個演算法被稱為bloom filter,基本上,它也只適合這樣的場合。這裡的大量是指有5000萬至1億的url,更大的資料量可能也不合適了。所以,把目標鎖定在單機排重,一開始,試驗了perl中的hash,非常簡單的 db file my db tie ...
快速URL排重的方法 二
接上篇,起初我為了輸入輸出方便,是用perl去實現的,後來發現perl中求模速度太慢,就改用c了 常量定義 space指你要分配多大的記憶體空間,我這裡是為5000萬資料的每一條分配4位元組 const intspace 50000000 4 const intmaxnum space 8 defi...
linux排重的方法
想必各位用linux的人都會碰到排重的問題,像檢視乙個日誌檔案,碰到很多重覆記錄,看起來很痛苦。還有像grep一下關鍵字,想找出現關鍵字的檔案,但是出現了一堆重複的檔名,也是一件鬱悶的事情。下面給大家介紹兩種linux排重的方法,一種是使用uniq命令,一種使用gawk。uniq排重 uniq的作用...