海量數據相關

以下基本來自左神的算法書

相關題目:

1.找到100億url中最多出現的k個

分析:

這個只是知道一個大致的思路,先把思路寫在這裏。

 在大規模數據處理中,經常會遇到的一類問題:在海量數據中找出出現頻率最高的前k個數,或者從海量數據中找出最大的前k個數,這類問題通常被稱爲top K問題。例如,在搜索引擎中,統計搜索最熱門的10個查詢詞;在歌曲庫中統計下載最高的前10首歌等。

針對top K類問題,通常比較好的方案是分治+Trie樹(字典樹,單詞查找樹)/hash+小頂堆(堆頂的值小於等於左右兩個節點的值,並且左右兩個子樹也是一個小頂堆),即先將數據集按照Hash方法分解成多個小數據集,然後使用Trie樹或者Hash統計每個小數據集中的query詞頻,之後用小頂堆求出每個數據集中出現頻率最高的前K個數,最後在所有top K中求出最終的top K。

原文來源:https://blog.csdn.net/zyq522376829/article/details/47686867

這裏在補充一下另一種使用快速排序的思路:

TopK是希望求出arr[1,n]中最大的k個數,那如果找到了第k大的數,做一次partition,就可以找到Topk個元素。

在快速排序中第一次進行切分(partition),劃分之後會返回這個元素在排序數組中的位置i:

i = partition(arr, 1, n);

如果i大於k,則說明arr[i]左邊的元素都大於k,於是只遞歸arr[1, i-1]裏第k大的元素即可;

如果i小於k,則說明說明第k大的元素在arr[i]的右邊,於是只遞歸arr[i+1, n]裏第k-i大的元素即可

2.只用20gb內存在20億個整數中找到出現次數最多的數

要求:內存限制爲2GB

分析:用哈希表進行存儲的時候,key是4B,value是4B,這樣當20億的數據都不相同時(極端情況)下2GB的內存就會不夠,因此態一次性用哈希表進行統計。解決方法是把20億個數的大文件用哈希函數分成16個小文件,根據哈希函數的性質,同一種數不可能被哈希到彤彤的小文件上,同時每一個小文件中不同的數一定不會大於2一種,雞舍哈希函數足夠好,然後對每一個小文件用哈希表來統計其中每一種數出現的次數,這樣我們就到得到了16個小文件中各自出現的次數最多的數,還有各自的統計,接下來只需要選出這16個小文件各自的第一名中出現次數最多的即可。

這個方法就是使用哈希算法將大文件劃分爲小文件處理。

 

原問題的解法:把大文件通過哈希函數分配到及其或者通過哈希函數把大文件拆分爲小文件,一直進行這種劃分知道劃分滿足要求。之後使用哈希表遍歷找出重複的URL或者進行排序,查看是否有重複的URL出現。

普衝題目就是一個topk問題了,使用哈希函數分流,用哈希表做詞頻統計,使用堆結構和外排序手段進行處理。

總結:

實際上,最優的解決方案應該是最符合實際設計需求的方案,在時間應用中,可能有足夠大的內存,那麼直接將數據扔到內存中一次性處理即可,也可能機器有多個核,這樣可以採用多線程處理整個數據集

 下面針對不同的應用場景,分析了適合相應應用場景的解決方案。

(1)單機+單核+足夠大內存

如果需要查找10億個查詢次(每個佔8B)中出現頻率最高的10個,考慮到每個查詢詞佔8B,則10億個查詢次所需的內存大約是10^9 * 8B=8GB內存。如果有這麼大內存,直接在內存中對查詢次進行排序,順序遍歷找出10個出現頻率最大的即可。這種方法簡單快速,使用。然後,也可以先用HashMap求出每個詞出現的頻率,然後求出頻率最大的10個詞。

(2)單機+多核+足夠大內存

 這時可以直接在內存中使用Hash方法將數據劃分成n個partition,每個partition交給一個線程處理,線程的處理邏輯同(1)類似,最後一個線程將結果歸併。

 該方法存在一個瓶頸會明顯影響效率,即數據傾斜。每個線程的處理速度可能不同,快的線程需要等待慢的線程,最終的處理速度取決於慢的線程。而針對此問題,解決的方法是,將數據劃分成c×n個partition(c>1),每個線程處理完當前partition後主動取下一個partition繼續處理,知道所有數據處理完畢,最後由一個線程進行歸併。

(3單機+單核+受限內存

這種情況下,需要將原數據文件切割成一個一個小文件,如採用hash(x)%M,將原文件中的數據切割成M小文件,如果小文件仍大於內存大小,繼續採用Hash的方法對數據文件進行分割,知道每個小文件小於內存大小,這樣每個文件可放到內存中處理。採用(1)的方法依次處理每個小文件。

(5)多機+受限內存

這種情況,爲了合理利用多臺機器的資源,可將數據分發到多臺機器上,每臺機器採用(3)中的策略解決本地的數據。可採用hash+socket方法進行數據分發。

從實際應用的角度考慮,(1)(2)(3)(4)方案並不可行,因爲在大規模數據處理環境下,作業效率並不是首要考慮的問題,算法的擴展性和容錯性纔是首要考慮的。算法應該具有良好的擴展性,以便數據量進一步加大(隨着業務的發展,數據量加大是必然的)時,在不修改算法框架的前提下,可達到近似的線性比;算法應該具有容錯性,即當前某個文件處理失敗後,能自動將其交給另外一個線程繼續處理,而不是從頭開始處理。

   top K問題很適合採用MapReduce框架解決,用戶只需編寫一個Map函數和兩個Reduce 函數,然後提交到Hadoop(採用Mapchain和Reducechain)上即可解決該問題。具體而言,就是首先根據數據值或者把數據hash(MD5)後的值按照範圍劃分到不同的機器上,最好可以讓數據劃分後一次讀入內存,這樣不同的機器負責處理不同的數值範圍,實際上就是Map。得到結果後,各個機器只需拿出各自出現次數最多的前N個數據,然後彙總,選出所有的數據中出現次數最多的前N個數據,這實際上就是Reduce過程。對於Map函數,採用Hash算法,將Hash值相同的數據交給同一個Reduce task;對於第一個Reduce函數,採用HashMap統計出每個詞出現的頻率,對於第二個Reduce 函數,統計所有Reduce task,輸出數據中的top K即可。

2.重複問題

在海量數據中查找重複的元素或者去除重複出現的元素也是常考的問題。針對此類問題可以使用位圖法實現。

在程序設計中,判斷數據是否重複,當集合數據量比較大時,可以採用位圖法。首先先掃描一次集合   ,找出集合中最大的元素,然後按照集合中最大元素max創建一個長度爲max+q的新數組,接着再次掃面數組,每次遇到一個元素,就將新數組下標爲元素值的位置設置爲1.

如果使用哈希表的話,最壞情況下這40億個數都不相同,那麼需要16GB的內存,不符合條件。

這個問題我們可以使用位圖的方法。首先申請一個大小爲4294967295的bit類型的數組bitArr,數組中的每一個位置值表示狀態1或者是0.這個類型的數組一共佔據500MB的空間滿足條件。在使用時,遍歷這40億個無符號數,比如說遇到700就把對應的bitArr[700]設置爲1.遍歷完成後需要再次遍歷哪個位置上沒被設置爲1那個數就沒有出現過。

進階問題:

(1)根據10GB的內存限制,確定統計區間的大小,就是第二次遍歷時的biArr大小

(2)利用區間計數的方式,找到那個計數不足的區間 ,在這個區間上肯定有沒有出現過的數。

(3)對這個空間上的數做bitMap映射,在遍歷bitMap,找到一個沒有出現過的數即可。

對於原問題,可以使用bitMap來表示數出現的情況。具體的說是申請一個長度爲4294967295的bit類型的數組bitArr,用兩個位置表示一個數字出現的次頻。這樣一共需要佔用1GB的空間。使用時,除此遇到num就將bitArr[num*2+1]和bitArr[num*2]設置爲01,第二次出現設置爲10,第三次出現設置爲11,以後在遇到時不改變。遍歷完成之後再進行遍歷,如果發現某個位置爲10那麼就可以找到出現了兩次的數。

補充題目和上一個問題的進階問題很類似,思路如下:

(1)根據10MB的內存限制,確定統計區間的大小,就是第二次遍歷時的biArr大小(在本題中長度是2MB)

(2)遍歷整個文件,利用區間計數的方式,統計出每個區間的個數,找到中位數可能出現的區間 k。

(3)再次遍歷整個文件,這次我們只關心上一步出現的區間k中的數統計區間中各個數出現的個數,這樣就可以找到中位數了。

3.海量數據排序問題

3.1數據庫排序

導入數據庫中,進行索引排序

操作簡單,方便,但運行速度慢,對數據庫設備要求高

3.2分治法

縮小了每次使用內存的大小,但是編碼複雜,速度也慢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章