海量数据处理(二) :常见海量数据处理方法
對于常見的海量數(shù)據(jù)處理方法,通常為以下幾種,下面的題解也會圍繞這幾種解法展開
- 位圖 / 布隆過濾器
- 字典樹 / 倒排索引
- 外部排序
- 分治 / 哈希切割 + 堆 / 排序
1. 給40億個不重復(fù)的無符號整數(shù),沒排過序。給一個無符號整數(shù),如何快速判斷一個數(shù)是否在這40億個數(shù)中。
當(dāng)我們看到這樣一個題目時,腦海中可能第一時間想到的就是排序 + 二分,但是要知道40億個無符號整數(shù)所占據(jù)的內(nèi)存空間達(dá)到了16G,這樣的數(shù)據(jù)是無法放進(jìn)內(nèi)存中進(jìn)行計算的,所以上面的方法無法實現(xiàn)。
我們需要用位圖來完成這道題,我們用一個位來表示一個整數(shù),所以40億個數(shù)據(jù)也僅僅只占用了500M,然后將所有的數(shù)據(jù)用直接定址法放入位圖中,并將放入的對應(yīng)位置1。當(dāng)進(jìn)行查詢時,只要位圖的對應(yīng)位置為1,則說明該數(shù)據(jù)在這40億個數(shù)據(jù)中。
2. 給定100億個整數(shù),設(shè)計算法找到只出現(xiàn)一次的整數(shù)?
這道題還是使用位圖來解決,但是由于我們需要找到只出現(xiàn)一次的整數(shù),此時對于每一個整數(shù)就存在著3種狀態(tài)(出現(xiàn)0次, 出現(xiàn)1次,出現(xiàn)多次),由于一個位只能表示兩種,所以我們需要對位圖進(jìn)行改造,此時變成用兩個位來映射一個數(shù)據(jù)。并且00代表出現(xiàn)0次,01代表出現(xiàn)1次,11代表出現(xiàn)多次。此時占據(jù)的空間是 1G
但是使用兩個位的位圖映射稍微有一點麻煩,所以可以考慮使用雙位圖來進(jìn)行解決,一個位圖就代表著一個位,組合起來就是我們需要的結(jié)果。做法如下
當(dāng)數(shù)據(jù)第一次出現(xiàn)時位圖1對應(yīng)位置置1,如果位圖1為1后再次出現(xiàn),則將位圖2對應(yīng)位置也置1,此時達(dá)到最終狀態(tài),對于后面的出現(xiàn)直接忽略。
3.給兩個文件,分別有100億個整數(shù),我們只有1G內(nèi)存,如何找到兩個文件交集?
100億個整數(shù)需要40G的內(nèi)存,所以我們這里還是使用位圖來解決。
方法1:將文件1的整數(shù)全部映射到位圖中,接著從文件2中讀取數(shù)據(jù),并在位圖中查詢該數(shù)據(jù),如果數(shù)據(jù)存在,則說明該數(shù)據(jù)是交集之一。內(nèi)存消耗500M。
方法2:將文件1和文件2中的整數(shù)分別映射到位圖1,位圖2中。接著遍歷兩個位圖,對每個位置按位與,如果為1則說明該整數(shù)是交集之一,內(nèi)存消耗1G。
4.位圖應(yīng)用變形:1個文件有100億個int,1G內(nèi)存,設(shè)計算法找到出現(xiàn)次數(shù)不超過2次的所有整數(shù)
此時的狀態(tài)有四種,出現(xiàn)次數(shù)為0,出現(xiàn)次數(shù)為1,出現(xiàn)次數(shù)為2,出現(xiàn)次數(shù)超過2。需要用到兩個位表示,所以還是使用第二題的雙位圖來進(jìn)行解決,00代表1次,01代表2次,10代表2次,11代表多次。消耗內(nèi)存1G。
5.給兩個文件,分別有100億個query,我們只有1G內(nèi)存,如何找到兩個文件交集?分別給出精確算法和近似算法
query一般為URL中的查詢字符串或者SQL中的查詢語句,假設(shè)每個query30個字節(jié),那么100億個query也得300G的內(nèi)存才能裝下,而我們只有1G,所以直接放棄裝入內(nèi)存直接比對的做法。
近似算法:對于字符串,也可以采用位圖的思路進(jìn)行對某個字符串進(jìn)行標(biāo)記,也就是使用布隆過濾器來進(jìn)行處理。但是由于數(shù)據(jù)過多且空間不足,可能會因為映射時映射到了其他數(shù)據(jù)的比特位上,導(dǎo)致造成誤判。所以當(dāng)一個數(shù)據(jù)不存在于布隆過濾器中,則它必定不存在,但是如果一個數(shù)據(jù)存在于布隆過濾器中,它也不一定存在,所以布隆過濾器是近似算法。
精確算法:如果要精確的進(jìn)行查找,那就必須得將數(shù)據(jù)放入內(nèi)存中,但是由于數(shù)據(jù)過大無法一次性放入,所以我們可以考慮對數(shù)據(jù)進(jìn)行切分。切割的方式有兩種,哈希切割和平均切割
平均切割: 平均切割不是一個很好的方法,但是它確實是我們很容易就能思考到的方法,我們將兩個文件中的數(shù)據(jù)平均切分為M份(能放入內(nèi)存),分別存儲到一個set中,然后以此將數(shù)據(jù)進(jìn)行比較。這種方法就需要以此對所有的數(shù)據(jù)進(jìn)行比對,效率會比較低
哈希切割: 這時就可以采取哈希切割的思路,使用字符串哈希算法進(jìn)行哈希映射,映射位置為i,則放入編號為i的文件中,對兩個文件都采用這樣的做法進(jìn)行切分,分別為Ai和Bi。
之后,由于我們使用的是同一種字符串哈希算法,所以相同的字符串必定會被映射到同一個編號下的文件中,所以我們只需要依次進(jìn)入編號相同的Ai和Bi文件中尋找交集即可。
6.給一個超過100G大小的log file, log中存著IP地址, 設(shè)計算法找到出現(xiàn)次數(shù)最多的IP地址? 與上題條件相同,如何找到top K的IP?如何直接用Linux系統(tǒng)命令實現(xiàn)?
統(tǒng)計次數(shù)我們首先想到的方法就是使用鍵值對的方式,將每一個string的ip地址與出現(xiàn)次數(shù)相關(guān)聯(lián),pair<string, int>,然后使用KV模型的Map進(jìn)行存儲。但是由于數(shù)據(jù)超過100個G,內(nèi)存中無法直接存下,所以我們需要對數(shù)據(jù)進(jìn)行切割。
我們可以使用哈希切割的方式來解決文件分片的問題。相同的IP地址必定會被映射到同一個文件中,所以我們依次讀取文件,使用Map進(jìn)行次數(shù)統(tǒng)計即可。
之后再進(jìn)行排序即可
Linux的命令如下
sort log_file | uniq -c | sort -nr | head -k首先使用sort log_file來將數(shù)據(jù)進(jìn)行一個排序,使得相同的IP地址全部靠在一起。接著使用uniq - c進(jìn)行去重,并將重復(fù)的次數(shù)顯示在每列的旁邊,通過這個次數(shù)來使用sort -nr進(jìn)行降序排序,使得出現(xiàn)次數(shù)最的IP地址在前面,然后使用head -k 獲取前k個IP地址即可。
7.100w個數(shù)中找出最大的100個數(shù)
由于100w個數(shù)據(jù)并不算多,可以存放進(jìn)內(nèi)存中,所以可以考慮以下解法
方法1:采用快排中的partition劃分思想,即單趟劃分后,樞軸s前面的數(shù)據(jù)都比他大,后面的數(shù)據(jù)都比他小,此時我們選取其中較大的那一部分,繼續(xù)劃分。當(dāng)劃分后前端的數(shù)據(jù)剛好等于100后劃分結(jié)束,對前端數(shù)據(jù)進(jìn)行排序即可得到結(jié)果。如果前端數(shù)據(jù)不足100,則從后端數(shù)據(jù)進(jìn)行排序后取出不足的那部分補(bǔ)上,再進(jìn)行排序即可。O(100w*100)
方法2:局部淘汰法,使用一個大小為100的小堆來完成,維護(hù)一個小堆,當(dāng)數(shù)據(jù)比堆頂也就是最小值大的時候,用新數(shù)據(jù)替換掉堆頂,然后調(diào)整堆的結(jié)構(gòu)。遍歷完所有數(shù)據(jù)后就可以得到前100的數(shù)據(jù)。O(100w*lg100)
方法3:局部淘汰法,使用插入排序來完成,首先取出前100個數(shù)據(jù)進(jìn)行排序,然后依次遍歷后面的數(shù)據(jù),如果數(shù)據(jù)大于最小值,則將最小值刪除,然后按照插入排序的思路將數(shù)據(jù)插入進(jìn)去。
O(100w*100)
8.海量數(shù)據(jù)分布在100臺電腦中,想個辦法高效統(tǒng)計出這批數(shù)據(jù)的TOP10。
解法與上一題類似,可以使用堆來完成
對于每一個電腦,都構(gòu)建一個大小為10的堆(選大的構(gòu)建小堆,選小的構(gòu)建大堆),選出當(dāng)前電腦的TOP10。接著將所有電腦的數(shù)據(jù)匯總起來,共1000個數(shù)據(jù),繼續(xù)用堆從其中選出TOP10
9.給上千個文件,每個文件大小為 1K—100M。給 n 個詞,設(shè)計算法對每個詞找到所有包含它的文件,你只有 100K 內(nèi)存
這題可以使用倒排索引來解決,即建立起單詞——文件的映射。
很簡單,只需要遍歷所有文章,如果文章中出現(xiàn)過查詢詞,則將文件號追加在對應(yīng)詞的倒排拉鏈中即可。如果100M的文件放不下內(nèi)存中,就對數(shù)據(jù)進(jìn)行切割后處理即可。
總結(jié)
以上是生活随笔為你收集整理的海量数据处理(二) :常见海量数据处理方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【项目介绍】搜索引擎
- 下一篇: 高级数据结构与算法 | 深度遍历搜索(D