1. 程式人生 > >海量資料處理例項

海量資料處理例項

在bat等大公司,基本所有業務的資料量級都很龐大,那麼如何在保證資料完整性的情況下快速處理成了一個通用的難題,這裡列舉幾個例子,大致反應一些處理思想。
1.一個檔案中,每一行有一個整數,有上億行,目的:統計出現次數超過三次的整數寫入到另一個檔案中。

分析:
(1)首先資料在檔案中,既然要統計,那麼有一個原則就是減少IO次數。
(2)其次資料量上億,記憶體中肯定不可能全放下。
(3)需要統計次數,那麼就需要知道每個整數的出現次數。
問題:既然記憶體中放不下每一個數據,那麼就沒辦法知道當前拿到的資料出現了幾次,也就不知道應不應該把它寫入到目標檔案中去。
思考:上億的資料無法存放在記憶體中,我們先縮小資料量級,100w的資料是可以放在記憶體中的,那麼我們是不是可以把上億的資料分成100份100w的資料分開處理呢。
解決思路:先輪詢一遍整個檔案,對資料進行分片,分片規則:0<= num <100w放一個檔案,100w<= num <200w放一個檔案,依此類推。那麼現在就會分為多個小檔案了,我們就可以一個一個處理了,總的會進行2次IO,時間複雜度就是2n了。(PS:分治的方法,需要遍歷兩次,也可以使用點陣圖,值需要遍歷一次,但點陣圖有限制,只能縮小32倍,2G記憶體最多可存放2^34個整數對應的位)

2.海量日誌資料,提取出某日訪問網站次數最多的IP

分析:
(1)日誌資料極其龐大,包括各種格式不一致的資料。
(2)需要統計每個IP的訪問次數,記憶體中肯定放不下當前的統計值,但是也不能放到外部儲存中,這樣會增加IO,並且效率會慢。
思考:一個ip32位,最多存在2^32次方個ip,可以採用分治的思想,比如IP模1000,再找出每個小檔案中次數最多的ip,最後從1000個ip中找到訪問次數最多的ip。(PS:分治的方法,類似於第一題)

3.搜尋引擎會通過日誌檔案把使用者每次檢索使用的檢索串都記錄下來,每個查詢串的長度為1~255個位元組,假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是1千萬,但如果除去重複後,不超過3百萬個。一個查詢串的重複度越高,說明查詢它的使用者越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的記憶體不能超過1G

分析:
(1)1G最多能放1024^2*4=4194304個查詢串,是足夠放不超過300w查詢串的資料的。
(2)然後需要在300w資料中找出前10大,即第k大問題,可以通過堆排序進行計算。
解決思路:使用hashmap,遍歷1000w記錄,得出300w查詢串的統計值。然後維護一個10大小的小根堆,遍歷300w次,每次與根對比,最後得出前10。(PS:採用trie樹,關鍵字域存該查詢串出現的次數,沒有出現為0。最後用10個元素的最小推來對出現頻率進行排序)

4.有一個1G大小的檔案,裡面每一行是一個詞,詞的大小不超過16位元組,記憶體限制大小是1M,返回頻數最高的100個詞

分析:
(1)最大的問題是記憶體僅1M,那麼能同時讀入記憶體的資料就不能超過1M,只能分片。
(2)需要的是統計每個詞出現的頻率。
(3)每個詞不超過16個位元組,那麼至少也就有1024^3/16=67108864個詞。
問題:分片應該如何分?如何從分片後的資料統計得出所有資料的頻數最高的詞。
思考:1g至少要分1024份才能保證每一份平均大小為1M,為避免出現部分檔案超出1M,我們可以取值再大一點。
解決思路:首先,取每個詞%5000,然後把每個詞按結果分別存到5000個小檔案中,這樣每個檔案大約200k,如果還有檔案大於1M,用這個方法繼續拆。然後對每個小檔案進行統計,按每個小檔案前100個詞帶統計結果存入統計檔案中,最後對這個檔案內容進行排序,得出前100。

5.給定a,b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4g,找出a,b檔案共同的url。

分析:
(1)50億個url需要5000000000*64 / (1024*1024*1024) ≈ 298G記憶體,也就是說每次只能處理單個檔案1/75的資料,即資料至少分片75份。
(2)需要找出a,b共同的url,所以難點在於如何檢索,如果以其中一個檔案為基準去遍歷至少也要(50億*75)次遍歷。
思考:使用url%1000,把a檔案中所有url分到(a0,a1,…a999)中,同樣b檔案也分到(b0,b1,…,b999)中,這樣每個檔案大概300M,這樣處理後,所有可能相同的url都在對應的小檔案中(a0-b0,a1-b1…a999-b999),因為不對應的小檔案不可能出現相同的url。然後對每個小檔案進行對比就ok了。

6.給40億個不重複的unsigned int的整數,沒排過序的,然後再給一個數,如何快速判斷這個數是否在那40億個數當中。

分析:
(1)給定的數是40億,一個特殊的值,是否有什麼特殊含義。40億個整數需要消耗40*10^8*4/1024^3 ≈ 14.9g記憶體。
(2)需要判斷一個數是否存在,那麼最好能直接在記憶體中檢索。
問題:記憶體中不足以放下所有的數。
思考:由於只需要判斷是與否,所以可以優先考慮“點陣圖演算法”,即一個整數用一個位來表示,存在為“1”,不存在為“0”。
解決思路:一個int值為4個位元組,一個位元組8bit,那麼一個int值為32位,就可以表示0~31這32個整數是否存在,下一個int值表示32~63這32個整數是否存在,依此類推。比如1565/32=48餘29,應該在第47個整數的第28位上,0表示不存在,1表示存在。這樣相當於節省記憶體32倍,需要的記憶體就為14.9g/32=476M,那麼我們可以申請512M的記憶體。
另一種解決思路:分桶。可以參考第一題的按照數值大小分,也可以用另一個方案如下:
一個int值32位,首先,按首位為“0”和為“1”分,然後分別存放在兩個檔案中;然後再按次位為“0”或為“1”分,又可以分為2個檔案了,這樣就可以分為4個檔案了,依次類推。其實就是一個二叉樹的結構,這個二叉樹最多可以有33層,也就是2^32,但是我們沒有必要分那麼細,因為2^32=42億了,已經超過了我們要處理的資料,我們可以折衷分為2^5=32個檔案即可,剛好512M記憶體足夠存放一個檔案的內容。這樣我們需要檢索一個數據的時候,可以先判斷一下它的前5位,然後通過二叉樹查詢到對應檔案,把該檔案對映到記憶體中,然後在記憶體中檢索。