海量資料處理技巧

2021-10-09 04:50:00 字數 3825 閱讀 5990

資料時代來臨,資料量的**式增長是最為顯著的特徵。當高效能硬體的普及還跟不上這樣的資料大潮時,如何在有限的時空資源內處理海量資料成為了電腦科學以及數理統計等領域最大的挑戰。

海量資料處理的困難用一句話概括,就是時空資源不夠。具體來說,

對於時間受限的問題,我們一般的解決辦法是高效的演算法配合恰當的資料結構,比如雜湊表,bloom filter,堆,倒排索引,tire樹);而對於空間受限的問題,一般的解決辦法是「大而化小,分而治之」的策略,既然一次性行不通,那就一部分一部分讀,每讀入一部分可以生成乙個小檔案,小檔案是可以直接讀入記憶體的,我們這樣分割大資料之後,再依次處理小檔案的資料。

注意,本文我只介紹對於海量資料執行一些簡單的資料處理(比如儲存,查重,排序,統計數量等)時的一些通用的方法,至於更複雜的計算,涉及具體演算法效能層面的東西,由於世界上演算法以千萬記,面對不同情況,又有著無數變形,所以不可能總結出來。

july的部落格 教你如何迅速秒殺掉:99%的海量資料處理面試題 對海量資料處理的方法進行了細緻的總結,這篇文章寫的非常全面,建議大家一讀。但我讀完之後,竊以為許多問題和解決思路有所重複,沒必要全部都詳細**。為了理清思路、抓重點,我將那篇文章中涉及的問題以及相應方法更加簡化地總結為如下7點。

解決問題:海量資料不能一次性讀入記憶體,而我們需要對海量資料進行的計數、排序等操作 

使用工具:hash函式(hash表);堆

這種方法是典型的「分而治之」的策略,也是解決空間限制最常用的方法。基本思路可以用下圖表示。先借助雜湊演算法,計算每一條資料的hash值,按照hash值將海量資料分布儲存到多個桶中(所謂桶,一般可以用小檔案實現)。根據hash函式的唯一性,相同的資料一定在同乙個桶中。如此,我們再依次處理這些小檔案,最後做合併運算即可(有點類似於map-reduce的思想)。

注:一般用hash函式將資料對映到桶的方法是:

bucketid=h(mi)  %  nbucketid=h(mi)  %  n

其中mimi為第ii條資料,bucket_id為桶標號,n為要設定的桶數量。關於桶數量(即小檔案數量)設定的基本的原則是:每個小檔案的大小比記憶體限制要小。比如處理1g的大檔案,記憶體限制為1m,那就可以把大檔案分成2000個小檔案(甚至更多),這樣每個小檔案的大小約500k(甚至更小),我們就可以輕鬆讀入記憶體處理了。下面看一些具體的例子:

問題1 top-k篩選:海量資料儲存於多個檔案,任何一條資料都可能存在於任何乙個檔案當中,現需要篩選出現的次數最多的kk條資料。 

解決思路

這裡之所以使用堆排序,也是為了能盡可能地提高排序效率。就上例而言,堆排序的時間複雜度為nklog(k)nklog⁡(k)

問題2 對比查重:現有a和b兩個大檔案,每個檔案都儲存著海量資料,要求給出a,b中重複的資料。 

解決思路

解決問題:當需要處理的是海量字串資料時,有時trie樹會比直接上面說的hash對映的策略更高效。 

使用工具:trie樹;堆

trie樹是一種非常強大的處理海量字串資料的工具。尤其是大量的字串資料中存在字首時,trie樹特別好用。trie樹在字典的儲存,字串的查詢,求取海量字串的公共字首,以及字串統計等方面發揮著重要的作用。用於儲存時,trie樹因為不重複儲存公共字首,節省了大量的儲存空間;用於以字串的查詢時,trie樹依靠其特殊的性質,實現了在任意資料量的字串集合中都能以o(len)o(len)的時間複雜度完成查詢(lenlen為要檢索的字串長度);在字串統計中,trie樹能夠快速記錄每個字串出現的次數。下面看幾個問題例項。

注:有關trie樹的詳細講解可以參考我之前的部落格 trie樹的構建和應用

問題3 資料去重:乙個超大檔案(不能直接讀入記憶體),裡面包含海量字串資料,但字串資料種類有限(可見含有大量重複),現需要對字串去重。並統計去重後每個字串出現的次數 

解決思路

至於trie樹在儲存,求取公共字首等方面的應用可以參考我上面給出的部落格,這裡不再贅述。

總結一下,trie樹對於海量字串資料,在資料種類有限(構建的trie樹可以完全讀入記憶體)時,能夠使我們輕鬆的進行儲存,查詢,計數等工作。

解決問題:資料字典的構建;判定目標資料是否存在於乙個海量資料集;集合求交 

使用工具:bloom filter;hash函式

以存在性判定為例,bloom filter通過對目標資料的對映,能夠以o(k)o(k)的時間複雜度判定目標資料的存在性,其中kk為使用的hash函式個數。這樣就能大大縮減遍歷查詢所需的時間。

注:有關bloom filter樹的詳細講解可以參考我之前的部落格 bloom filter原理與實現,下面我假設你已經知道了bloom filter的工作原理。直接看問題4:

問題4 集合求交:與上面的問題2類似,只不過現在不是a和b兩個大檔案,而是a, b, c, d….多個大檔案。 

解決思路

問題5 unsigned int型整數存在性判定:判定乙個unsigned int型整數是否在乙個大的unsigned int型整數資料集中。 

解決思路

問題5用的其實是一種簡化了的bloom filter,不再採取hash對映的方式,而是直接根據整數的大小確定要改變的位數,這在某些特殊情況下(比如資料種類不多時)非常有效。

解決問題:海量資料求取第kk大數 

使用工具:hash函式

多層桶結構其實和最開始我們用hash對映分割大檔案的思路是一致的,都是一種「分而治之」的策略。只不過多層桶結構是對有些桶分割之後再分割,構成了一種層次化的結構,它主要應用於一次分割的結果依然不能解決記憶體限制的情況。比如下面的問題6:

問題6 求取海量整數的中位數。

解決思路

這個不詳細說了,在文件資料的檢索,尤其是關鍵字查詢領域有著極為廣泛的應用。其實這個思路也可以推廣開來,當存在海量的檔案,且每個檔案包含的資料種類有限,而我們的任務又是依據資料查檔案時,倒排索引都可以排上用場。

解決問題:海量資料的排序 

實用工具:歸併演算法

外排序是經典的排序方法之一,主要是針對大資料不能直接讀入記憶體的情況,通過記憶體與外存之間的資料交換,實現海量資料排序的。我大致介紹一下外排序的演算法思路,詳細的解釋可以參照部落格:排序之外部排序

問題7 海量資料排序。

解決思路

mapreduce是一種計算模型,分為」map」和」reduce」兩個階段。

這樣做的好處是可以在任務被分解後,可以通過大量機器進行平行計算,從而突破時間或者空間的限制。時間上顯然更快,空間上,單個機器只需要處理空間允許的資料量即可。舉個簡單的例子就是歸併排序,我們先將資料集分割成小資料集,使用多個機器排序每個分割後的小資料集(map),再將處理好的歸併段依次歸併(reduce)。

本文求盡量全面總結海量資料處理的思路,不求對每種思路的深入**。因為這些方法要麼在我之前的部落格中已有詳細說明,要麼比較通用,網上的介紹很充分。

不得不說海量資料處理時,面臨的問題是千變萬化的,所以本文也會持續更新,希望讀者們也能不斷補充我遺漏的知識。

海量資料處理

1 有一千萬條簡訊,有重複,以文字檔案的形式儲存,一行一條,有 重複。請用5分鐘時間,找出重複出現最多的前10條。方法1 可以用雜湊表的方法對1千萬條分成若干組進行邊掃瞄邊建雜湊表。第一次掃瞄,取首位元組,尾位元組,中間隨便兩位元組作為hash code,插入到hash table中。並記錄其位址和...

海量資料處理

給定a b兩個檔案,各存放50億個url,每個url各占用64位元組,記憶體限制是4g,如何找出a b檔案共同的url?答案 可以估計每個檔案的大小為5g 64 300g,遠大於4g。所以不可能將其完全載入到記憶體中處理。考慮採取分而治之的方法。遍歷檔案a,對每個url求取hash url 1000...

海量資料處理

分而治之 hash對映 hash統計 堆 快速 歸併排序 300萬個查詢字串中統計最熱門的10個查詢。針對此類典型的top k問題,採取的對策往往是 hashmap 堆。hash統計 先對這批海量資料預處理。具體方法是 維護乙個key為query字串,value為該query出現次數的hashtab...