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


  隨着現在數據量的不斷增加,很多大數量的問題隨之而來,就得需要我們想辦法解決,我找了一些問題並首先思考,然后找到方法,在這里記錄一下,未來有需要的同學可以拿走去用。

  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)解決。

    以電話號碼為例:

    a)電話號碼是8位數字,也就是出現的數字應該為11111111-99999999,總數為99999999,咱們采用位圖法(因為最省內存)。

    b)一個bit位代表一個數字,那么這些數字共需要99999999個bit,占用內存為 99999999/8/1024/1024約等於11.92M,即如果這個數字所在的位有數據,那么這個bit位就設置為1,否則設置為0。

    這樣只需要12M的內存就可以統計這些數據了。當然2.5億整數同理,在內存中所有整數的個數為2^32,一個數對應一個bit,大概需要512M內存就可以了,如果給的內存還不夠的話,則需要再次進行拆分。

  3. 還有一些與上邊類似的,但是不太相同的,因為有重復的數(1、2、2、3、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)。

 

如果有不對的地方,歡迎指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM