海量數據處理方法整理記錄

  隨着如今數據量的不斷增長,不少大數量的問題隨之而來,就得須要咱們想辦法解決,我找了一些問題並首先思考,而後找到方法,在這裏記錄一下,將來有須要的同窗能夠拿走去用。算法

  1. 在海量日誌數據裏,提取某天訪問量最多的IP。數組

  通常處理海量的思路都是分治處理,就是現將數據進行拆分,而後進行處理,排序等。這個例子也不例外,IPV4的地址一共32位,最大值爲2^32也就是總數大約4G左右,若是放到內存裏邊,以目前的內存容量也是能夠處理的,可是我們能夠爲本身設置一些條件,好比目前沒有那麼多內存。分佈式

    a) 首先分治,將這個文件按照IP的HASH分紅1024份(若是想要均勻的分的算法須要使用一致性Hash算法),這樣每一個文件大約4M左右而且存放到磁盤上去。日誌

    b) 構建一個須要以IP爲Key,出現次數爲Value的TreeMap。讀取每一個文件,將IP和出現次數放入有序的TreeMap。排序

    c) 這樣就能夠獲得出現次數最多的IP,前N個出現次數多的IP均可以獲取到了。內存

  這種問題通常是TOP K的問題,思路均可以按照這樣的思路去解決。固然這種場景比較合適的就是Map Reduce莫屬了。另外,關於TOP K的這種排序的話能夠採用最小堆排序(即根節點是最小的),它的時間複雜度爲n*mlogm,n即爲一共多少數據,m爲取出前m個數據。關於這種結構不知道的同窗能夠進行谷歌搜索。分治的做用就是爲了減小使用系統的資源,好比系統內容。資源

  2. 上個問題是統計重複出現的個數,那麼如何統計不重複的個數。好比:有個電話本,裏邊記錄的電話號碼都是8位數字,統計電話本里邊有多少電話號碼?這個裏邊確定也是有一些侷限的,好比內存限制。再好比再2.5億整數中找到不重複的整數的個數,固然,內存中不可以存儲着2.5億數據。這種解決的思路通常是位圖算法(bitMap)解決。字符串

    以電話號碼爲例:hash

    a)電話號碼是8位數字,也就是出現的數字應該爲11111111-99999999,總數爲99999999,我們採用位圖法(由於最省內存)。it

    b)一個bit位表明一個數字,那麼這些數字共須要99999999個bit,佔用內存爲 99999999/8/1024/1024約等於11.92M,即若是這個數字所在的位有數據,那麼這個bit位就設置爲1,不然設置爲0。

    這樣只須要12M的內存就能夠統計這些數據了。固然2.5億整數同理,在內存中全部整數的個數爲2^32,一個數對應一個bit,大概須要512M內存就能夠了,若是給的內存還不夠的話,則須要再次進行拆分。

  3. 還有一些與上邊相似的,可是不太相同的,由於有重複的數(一、二、二、三、三、4,排好序的數而且偶數個的話,中位數是[2+3]/2=2.5 奇數個的話正好是中間的),好比在5億int數中找到中位數。這個問題的解決思路其實採用雙層桶劃分思路。注意一個int佔4個Byte,整數的最大位數爲32位,那麼咱們將每一個數轉換爲二進制,而後截取前多少位,要看內存大小。解決思路:

    a) 把整數轉爲二進制數,而後截取前5位,那麼總共分出2^5=32個區間,若是分出文件來共分出32個文件,若是內存不夠的話,那麼再繼續截取(好比16位,這裏舉例)。好比:file_00000, file_00001等。

    b) 若是截取完了,全部文件一共32個文件,由於都是二進制,因此文件是按照有序排好的。統計每一個文件的個數,而後計算中位數所在的文件裏。

    c) 若是文件仍是比較大,假設文件在最後一個文件,即前邊2.5億,最後一個文件2.5億,文件名字爲file_11111,那麼再繼續按照上邊的方法繼續拆分(好比再5位 文件名:file_11111_00000 等),知道內存中能夠裝下整個文件。

    d) 能夠裝下整個文件下的話再進行排序,排好序以後,找到中間的數就是中位數。

  4. 兩個文件,各存放50億條URL,每一個URL佔64字節。內存限制是4G,找出兩個文件中相同的URL。這個問題有一個內存限制,那麼確定須要分治法。

    方法一(分治+hash+hashset):

    a) 50億個64Byte= 5G*64Byte = 320G,內存4個G,確定是不能夠的。那麼我們將每一個URL進行hash,而後放到1024個文件中,也就是每一個文件爲320G/1024=320M左右。以hash值做爲文件名,第一個文件hash出來的文件命名爲(hash[URL]%1024)a1.....a1024,第二個文件hash出來的文件命名爲b1.....b1024。

    b)1024個文件生成了,那麼相同的URL確定在hash命名文件的後綴中,好比a1 vs b1,這樣依次讀取文件的內容放入到hashset中,若是存在的話記錄而且追加放到文件中。

    c)  最後文件中就是全部URL即爲相同的URL。

    方法二(Bloom Filter布隆過濾器)

    a) 先說一下布隆過濾器,主要將須要內容進行hash,而後對應到相應的bit上,即Bit Map位圖法,可是這個裏邊有一個問題就是hash會碰撞,即不一樣的結果可能會hash成相同的值,這樣就會出錯。若是能夠接受錯誤率,固然錯誤率較低,那麼能夠採用這種方式。4G內存=2^32 * 8 約等於 40億Byte * 8 大約等於340億。先遍歷第一個文件,而後再遍歷第二個,這樣會錯誤率。

  5. 有40億個不重複的unsigned int的整數,沒排過序,如今給一個數,如何快速判斷這個數是否在這40億個數當中。這個若是直接放到內存裏邊的話得須要2^32*4Byte(int 4Byte) = 4G *4 = 16G. 顯然內存比較大了。

    a) 這個也採用位圖法,所須要的內存爲  2*32Byte / 8 = 500M 內存,因此僅僅須要500M內存就能夠放下這些數字了,而後查找就能夠了。

  6. 給定一個文件,裏面最多含有n個不重複的正整數(也就是說可能含有少於n個不重複正整數),且其中每一個數都小於等於n,n=10^7。輸出:獲得按從小到大升序排列的包含全部輸入的整數的列表。條件:最多有大約1MB的內存空間可用,但磁盤空間足夠。且要求運行時間在5分鐘如下,10秒爲最佳結果。

  若是採用位圖法的話須要爲10^7 / 8 /1024/1024 大約等於1.19M,大於題目的1M,顯然位圖法不太合適,那麼我們考慮一下多路歸併排序。

  a)  首先將這個文件分批次讀取拆分,好比一次讀取256K,而後進行memory sort 在內存排序,寫到文件中。假如文件大小是10M的大小,則須要循環40次,寫入40個文件當中。

  b)  而後將文件進行merge sort合併排序,建立一個數組40個長度,依次讀取最小的文件,而後找到數組中最小的寫入到文件當中,而後繼續讀取文件而且繼續排序,將最小的再次寫入文件便可。

  6. 有10個文件,每一個文件1G,每一個文件的每一行都存放的是用戶的搜索的關鍵字,每一個文件的搜索的關鍵字均可能重複。找出熱度高的前1000個搜索關鍵字。(提示分治+hash+trie樹+最小堆)

  看到這種問題的話,首先得考慮是否機器資源足夠使用,若是足夠使用的話,就直接加入內存,可是若是不夠的話須要考慮分治。解決思路。

  a) 將每一個文件按關鍵字進行hash,而後拆分紅100個文件,而後每一個文件大概100M左右。(分治+hash)。

  b) 讀取每一個小文件,而且將讀取的關鍵字造成Trie樹字典樹,這樣會達到去重的效果。Trie樹的插入和查詢複雜度是O(k), k爲最長字符串的長度。而後創建長度爲1000的小根堆,將遍歷每一個關鍵字的出現的次數放到小根堆裏。

  c) 以上一遍就能夠得出第一個1G文件的結果,而後按照相同的原理繼續以上步驟。

 

總結一下:

  若是是大量數據不重複的,並且須要內存佔用比較少的須要找出出現的內容的話,適合使用BitMap位圖法進行處理。

  還有就是通常的TOP K問題,就是找出前多少位的這種,通常內存容量都不是很大,採用的方式是 分治+hash+最小(大)堆排序。固然分佈式的適合處理方式爲MapReduce處理。

  排序能夠有不少種,按照不一樣的方式進行不一樣的排序,好比快排,最小堆排序,歸併排序。若是大文件須要排序,而且嚴格要求內存的話,分治成小文件,而後採用歸併排序很合適。

  若是涉及到單詞的類型處理的話,須要使用Trie樹進行,由於這個很是合適處理,而且複雜度爲O(k)。

 

若是有不對的地方,歡迎指正。

相關文章
相關標籤/搜索