2. 當前解決方案
針對top k類問題,通常比較好的方案是【分治+trie樹/hash+小頂堆】,即先將資料集按照hash方法分解成多個小資料集,然後使用trie樹或者hash統計每個小資料集中的query詞頻,之後用小頂堆求出每個資料集中出頻率最高的前k個數,最後在所有top k中求出最終的top k。
實際上,最優的解決方案應該是最符合實際設計需求的方案,在實際應用中,可能有足夠大的記憶體,那麼直接將資料扔到記憶體中一次性處理即可,也可能機器有多個核,這樣可以採用多執行緒處理整個資料集。
本文針對不同的應用場景,介紹了適合相應應用場景的解決方案。
3.2 單機+多核+足夠大記憶體
這時可以直接在記憶體中實用hash方法將資料劃分成n個partition,每個partition交給乙個執行緒處理,執行緒的處理邏輯是同3.1節類似,最後乙個執行緒將結果歸併。
該方法存在乙個瓶頸會明顯影響效率,即資料傾斜,每個執行緒的處理速度可能不同,快的執行緒需要等待慢的執行緒,最終的處理速度取決於慢的執行緒。解決方法是,將資料劃分成c*n個partition(c>1),每個執行緒處理完當前partition後主動取下乙個partition繼續處理,直到所有資料處理完畢,最後由乙個執行緒進行歸併。
3.3 單機+單核+受限記憶體
這種情況下,需要將原資料檔案切割成乙個乙個小檔案,如,採用hash(x)%m,將原檔案中的資料切割成m小檔案,如果小檔案仍大於記憶體大小,繼續採用hash的方法對資料檔案進行切割,直到每個小檔案小於記憶體大小,這樣,每個檔案可放到記憶體中處理。採用3.1節的方法依次處理每個小檔案。
3.4 多機+受限記憶體
這種情況下,為了合理利用多台機器的資源,可將資料分發到多台機器上,每台機器採用3.3節中的策略解決本地的資料。可採用hash+socket方法進行資料分發。
從實際應用的角度考慮,3.1~3.4節的方案並不可行,因為在大規模資料處理環境下,作業效率並不是首要考慮的問題,演算法的擴充套件性和容錯性才是首要考慮的。演算法應該具有良好的擴充套件性,以便資料量進一步加大(隨著業務的發展,資料量加大是必然的)時,在不修改演算法框架的前提下,可達到近似的線性比;演算法應該具有容錯性,即當前某個檔案處理失敗後,能自動將其交給另外乙個執行緒繼續處理,而不是從頭開始處理。
top k問題很適合採用mapreduce框架解決,使用者只需編寫乙個map函式和兩個reduce 函式,然後提交到hadoop(採用mapchain和reducechain)上即可解決該問題。對於map函式,採用hash演算法,將hash值相同的資料交給同乙個reduce task;對於第乙個reduce函式,採用hashmap統計出每個詞出現的頻率,對於第二個reduce 函式,統計所有reduce task輸出資料中的top k即可。
4. 總結
top k問題是乙個非常常見的問題,公司一般不會自己寫個這裡寫**片
程式進行計算,而是提交到自己核心的資料處理平台上計算,該平台的計算效率可能不如直接寫程式高,但它具有良好的擴充套件性和容錯性,而這才是企業最看重的。
5. 參考資料
《十道海量資料處理面試題與十個方法大總結》:
本部落格的文章集合:
怎樣從10億查詢詞找出出現頻率最高的10個
1 問題描述 2 當前解決方案 針對top k類問題,通常比較好的方案是 分治 trie樹 hash 小頂堆 即先將資料集按照hash方法分解成多個小資料集,然後使用trie樹或者hash統計每個小資料集中的query詞頻,之後用小頂堆求出每個資料集中出頻率最高的前k個數,最後在所有top k中求出...
如何從10億查詢詞找出出現頻率最高的10個?
1 問題描述 2 當前解決方案 針對top k類問題,通常比較好的方案是 分治 trie樹 hash 小頂堆 即先將資料集按照hash方法分解成多個小資料集,然後使用trie樹或者hash統計每個小資料集中的query詞頻,之後用小頂堆求出每個資料集中出頻率最高的前k個數,最後在所有top k中求出...
談從10億個數中找出前10萬個最大的
10億個浮點數大概佔據3g左右的空間,因此全部一次性讀入記憶體目前在個人pc上是不太現實的。本次討論不考慮記憶體等等,只考慮演算法。如果一次性比較排序,然後輸出前面最大的10w個,那麼眾所周知,演算法的時間複雜度不下於o n lgn 此處的n為數的個數 10億 如果用堆排序,由於堆排序像合併排序而不...