場景描述:在某場景下有乙個使用者關係鏈,比如a關注了b,然後b關注了c,然後使用者b知道自己被誰關注,也知道他關注了誰。假如說將這個資訊放在統一的資料庫中,然後使用者查詢的時候每次去遍歷,那麼就會對資料庫造成非常大的負擔,而且在乙個億級使用者系統中這樣的時間延遲是不可接受的。這種情況下我們可以為每個使用者維護兩個集合:乙個是他關注的人,乙個是他被誰關注了。這裡也會出現乙個問題:假如a關注了b,那麼一次關注就要寫兩個資料,乙個是a的關注列表,乙個是b的被關注列表,如果說中間由於網路或者其他某些原因導致其中乙個寫操作丟失,後面要怎麼排查出那個丟失的寫操作?
解決方案:使用歸併排序來處理,內排外排都行。假定a關注了b,那麼就會產生兩個資料(a,b)、(a,b),乙個放在a的關注列表中,乙個放在b的被關注列表中,他們都是成對出現。我們每隔一段時間就批量將所有使用者的關注列表和被關注列表讀取出來,然後進行歸併排序,只要在歸併的過程**現了成對的資料,就把成對的資料拋棄掉,這樣一直歸併下去最後剩下的就是不成對的資料。最後我們根據這個不成對的資料去把它們補全即可。
場景描述:在2.5億個整數中找出不重複的整數,注,記憶體不足以容納這2.5億個整數。
解決方案1:採用2-bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)進行,共需記憶體2^32 * 2 bit=1 gb記憶體,還可以接受。然後掃瞄這2.5億個整數,檢視bitmap中相對應位,如果是00變01,01變10,10保持不變。所描完事後,檢視bitmap,把對應位是01的整數輸出即可。
解決方案2:用雜湊或者取模將2.5億個整數分到小檔案中,然後在小檔案中找出不重複的整數,並排序。然後再進行歸併,注意去除重複的元素。
原理:當乙個元素被加入集合時,通過k個雜湊函式將這個元素對映成乙個位陣列中的k個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何乙個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。它實際上是乙個很長的二進位制向量和一系列隨機對映函式。優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。
場景描述:給你a,b兩個檔案,各存放50億條url,每條url占用64位元組,記憶體限制是4g,讓你找出a,b檔案共同的url。如果是三個乃至n個檔案呢?
解決方案:如果允許有一定的錯誤率,可以使用bloom filter,4g記憶體大概可以表示340億bit。將其中乙個檔案中的url使用bloom filter對映為這340億bit,然後挨個讀取另外乙個檔案的url,檢查是否與bloom filter,如果是,那麼該url應該是共同的url(注意會有一定的錯誤率)。
在這裡的話另外引入乙個場景:知乎首頁的推送是不重複的,那麼在獲取到內容之後要把使用者已讀文章過濾掉,如果說用所有的文章乙個個去使用者已讀列表中查詢這樣的效率太低了。那麼可以為每乙個使用者維護乙個布隆過濾器,然後用布隆過濾器去對文章進行過濾。當然可能並不完美,因為布隆過濾器也會占用記憶體,以及需要對其進行維護更新,否則短時間內使用者重新整理兩次就很多重複文章了,這個可能不是知乎現在的方案。
其他應用場景:
場景描述:在5億個int中找它們的中位數
解決方案一:首先我們將int劃分為2^16個區域,然後讀取資料統計落到各個區域裡的數的個數,之後我們根據統計結果就可以判斷中位數落到那個區域,同時知道這個區域中的第幾大數剛好是中位數。然後第二次掃瞄我們只統計落在這個區域中的那些數就可以了。
實際上,如果不是int是int64,我們可以經過3次這樣的劃分即可降低到可以接受的程度。即可以先將int64分成224個區域,然後確定區域的第幾大數,在將該區域分成220個子區域,然後確定是子區域的第幾大數,然後子區域裡的數的個數只有2^20,就可以直接利用direct addr table(第n個數存放在第n個位置)進行統計了。
解決方案二:方法同基數排序有些像,開乙個大小為65536的int陣列,第一遍讀取,統計int32的高16位的情況,也就是0-65535,都算作0,65536 - 131071都算作1。就相當於用該數除以65536。int32 除以 65536的結果不會超過65536種情況,因此開乙個長度為65536的陣列計數就可以。每讀取乙個數,陣列中對應的計數+1,考慮有負數的情況,需要將結果加32768後,記錄在相應的陣列內。
第一遍統計之後,遍歷陣列,逐個累加統計,看中位數處於哪個區間,比如處於區間k,那麼0- k-1的區間裡數字的數量sum應該場景描述:100w個數中找出最大的100個數。
解決方案一:區域性淘汰方法。選取前100個元素,並排序,記為序列l。然後一次掃瞄剩餘的元素x,與排好序的100個元素中最小的元素比,如果比這個最小的要大,那麼把這個最小的元素刪除,並把x利用插入排序的思想,插入到序列l中。依次迴圈,知道掃瞄了所有的元素。複雜度為o(100w*100)。
解決方案二:採用快速排序的思想,每次分割之後只考慮比軸大的一部分,知道比軸大的一部分在比100多的時候,採用傳統排序演算法排序,取前100個。複雜度為o(100w*100)。
解決方案三:用乙個含100個元素的最小堆來完成。複雜度為o(100w*lg100)
bitmap去重與布隆過濾器
通過乙個位元位來存乙個位址,占用記憶體很小 bloomfilter 會開闢乙個m位的bitarray 位陣列 開始所有資料全部置 0 當乙個元素過來時,能過多個雜湊函式 h1,h2,h3.計算不同的在雜湊值,並通過雜湊值找到對應的bitarray下標處,將裡面的值 0 置為 1 python中使用布...
bitmap實現大資料排序和去重
要點 假如有10億元素,全部資料讀進記憶體,占用 1000000000 4 1024 1024 1024 3.725 g,解決方法 bitmap演算法,每一位都能表示一位數字,10000000000 8 1024 1024 1024 0.116 g,節約了31倍的空間!define sizebit ...
scrapy redis的布隆去重
為什麼要使用布隆去重?scrapy自帶去重機制,即將所需要爬取的網頁放在set中來達到去重的目的,但是在實際工作中,我們需要更新資料的時候往往不需要爬取已經爬取過的頁面,這時候set去重就達不到目的了,會造成重複爬取url,所以我們要用到布隆去重。布隆去重的優點和缺點優點 相比於其它的資料結構,布隆...