(1)檔案太大,100g,肯定不可能一次載入到記憶體進行處理,這裡就必須將檔案進行切割了,可是依據哪種方法進行切割呢?假設只是從前到後等份切割的話,將檔案切割n份(切割的份數依據所給的記憶體大小),第乙份中假設ip位址為a出現次數最多,第二份中b出現的次數最多,這樣比較出來,假設a比b大,那得出的結果就是ip位址為a的出現次數多,可是?假設第乙份中也有位址為b的ip呢?這樣分割出來的檔案,不能保證相同ip位址被分到同乙個檔案當中,這樣算出的結果就肯定不正確了。
這裡我們應該想到使用雜湊的思想,我們可以給出n個檔案,(n的取值取決於給定的記憶體大小),將點分十進位制的ip位址轉化為整數,利於雜湊函式(雜湊函式採用直接定址法),求出ip位址所對應檔案的編號,這樣將所有位址分派到不同編號的檔案中,相同的位址一定在同乙個檔案當中,依次遍歷每個檔案,統計出每個ip位址出現的次數,這樣就可以找到出現次數最多的ip位址。
(2)top k問題的解決辦法我們很容易想到用堆,首先,搞清楚是要出現次數最多的k個ip還是出現次數最少的k個ip。如果是最多的,可以給小堆,如果最少的,給的就是大堆;假設這裡我們要的是出現次數最多的k個ip,在第一問中,我們已經求出了每個ip位址出現的次數,將這些ip位址和出現次數封裝為乙個結構體(鍵值對),給乙個只能容納k個鍵值對的小堆,在向堆中插入元素時,ip位址出現的次數作為關鍵碼,先向堆中插入k個元素,以後再插入元素時,先於堆頂元素進行比較,如果小於堆頂元素,不做處理;如果大於,則將堆頂元素刪除,將此元素重新插入堆中,當遍歷完所有ip位址後,堆中儲存的元素就是出現次數最多的k個。
①分治:ip是32位,共有2^32個ip。訪問該日的日誌,將ip取出來,採用hash,比如模1000,把所有ip存入1000個小檔案。
②hash_map:統計每個小檔案中出現頻率最大的ip,記錄其頻率。
③小頂堆:這裡用乙個變數即可。在這1000個小檔案各自最大頻率的ip中,然後直接找出頻率最大的ip。
分析:雖然資料已經是分布的,但是如果直接求各自的top10然後合併的話,可能忽略一種情況,即有乙個資料在每台機器的頻率都是第11,但是總數可能屬於top10。所以應該先把100臺機器中相同的資料整合到相同的機器,然後再求各自的top10並合併。
①分治:順序讀每台機器上的資料,按照hash(x)%100重新分布到100臺機器內。接下來變成了單機的topk問題。單台機器內的檔案如果太大,可以繼續hash分割成小檔案。
②hash_map:統計每台機器上資料的頻率。
③小頂堆:採用容量為10的小頂堆,統計每台機器上的top10。然後把這100臺機器上的top10組合起來,共1000個資料,再用小頂堆求出top10。
方法1:用容量為100的小頂堆查詢。複雜度為o(100w * lg100)。小堆是最好的方法。
方法2:採用快速排序的思想,每次分割之後只考慮比標兵值大的那一部分,直到大的部分在比100多且不能分割的時候,採用傳統排序演算法排序,取前100個。複雜度為o(100w*100)。
方法3:區域性淘汰法。取前100個元素並排序,然後依次掃瞄剩餘的元素,插入到排好序的序列中,並淘汰最小值。複雜度為o(100w * lg100) (lg100為二分查詢的複雜度)。
分析:每個檔案的大小約為5g×64=320g,遠遠大於記憶體大小。考慮採取分而治之的方法。
①分治:遍歷檔案a,對每個url求hash%1000,根據值將url分別儲存到1000個小檔案中,每個小檔案約為300m。檔案b採用同樣hash策略分到1000個小檔案中。上述兩組小檔案中,只有相同編號的小檔案才可能有相同元素。
②hash_set:讀取a組中乙個小檔案的url儲存到hash_set中,然後遍歷b組中相同編號小檔案的每個url,檢視是否在剛才構建的hash_set中。如果存在,則存到輸出檔案裡。
1gb記憶體:
①bitmap:對於32位的整數,共有2^32個,每個數對應乙個bit,共需0.5gb記憶體。遍歷檔案,將每個數對應的bit位置1。最後查詢0bit位即可。
10mb記憶體: 10mb = 8 × 10^7bit
①分治:將所有整數分段,每1m個數對應乙個小檔案,共4000個小檔案。注意計算機能表示的所有整數有4g個。
②hash_set:對每個小檔案,遍歷並加入hash_set,最後如果set的size小於1m,則有不存在的數。利用bitmap查詢該數。
注:計算機能表示的整數個數一共有4g個,整數域hash分割成10m乙個檔案,,一共分割成400個小檔案,每個小檔案判斷不存在的數,再把這些數全都歸併起來。磁碟io次數越少越好!!所以不明白為啥1m對應乙個小檔案,而不取最大的10m。
假設這裡是32位機,32位機中整形所能表示數字最大個數為2的32次方,我們可以使用點陣圖來表示乙個數的狀態,每個數給兩個位元位,00表示這個數不存在,01表示這個數出現一次,10表示這個數出現多次,這樣所需空間大小為1g(2^64bit)
與第一問一樣,我們可以使用位圖思想,這裡只需要乙個位元位來表示乙個數存在與否,將兩個檔案的資料分別對映到兩個位圖當中,將兩個點陣圖按位與,得出的結果就是兩個檔案的交集。
與第一問一樣,也是用兩個位元位表示乙個資料的狀態。00表示不存在,01表示只出現一次,10表示出現兩次,11表示出現兩次以上,將每個資料對映到位圖當中,最後遍歷位圖,就可以得出結果。
精確演算法:
乙個query(查詢記錄)字串大概算60位元組,100億大概600g,那麼我們可以進行雜湊切割,給出6000(數目越多,越不容易發生雜湊衝突,結果越準確)個檔案,將字串轉化為整數,採用除留餘數法,將每個字串儲存到對應編號的檔案當中,然後再遍歷第二個檔案,拿到乙個字串,用相同的辦法找到它所對應的檔案,再到對應的檔案當中找是否有與其相同的字串,這樣就找到了兩個檔案的交集。
近似演算法:
可以採用布隆過濾器,(即位圖與雜湊聯絡起來),將第乙個檔案當中的每乙個字串插入到布隆過濾器當中,然後,再到第二個檔案當中,遍歷每乙個query,到布隆過濾器中查詢詞條query中是否存在。這樣就可以近似找到兩個檔案的交集。因為,在布隆過濾器中查詢某乙個元素,如果查詢結果位不存在,那麼就一定不存在,但是如果結果為存在,其實也有可能不存在,所以這種解法位近似演算法。
可以給每乙個元素分配多個位元位,例如:每個元素分配兩個位元位,00表示不存在,01表示有乙個,10表示有兩個,如果要刪除某個元素,給其減一,如10變為01。
與上題思路一致。
可以將每個檔案中的詞都插入到布隆過濾器中,再用所給的n個詞再布隆過濾器中查詢。
typedef
struct filenodefilenode;
typedef
struct hashnodehashnode;
typedef strut hashtablehashtable;
海量資料問題
在海量資料中查詢出重複出現的元素或者去除重複出現的元素也是常考的問題。針對此類問題,一般可以通過位圖法實現。例如,已知某個檔案內包含一些 號碼,每個號碼為8位數字,統計不同號碼的個數。本題最好的解決方法是通過使用位圖法來實現。8位整數可以表示的最大十進位制數值為99999999。如果每個數字對應於位...
海量資料問題總結
這個是一系列問題,網際網路公司,一些基本的功能都已經做的很完善了,海量資料處理成為重點的問題,也是面試筆試中常考的題目。主要參考 1.分而治之 hash對映 hash統計 堆 快速 歸併排序 hash對映很重要,分類後的資料不會分散,某乙個類別的資料會全部在一起。用hash map統計的速度要比ma...
海量資料問題總結
這個是一系列問題,網際網路公司,一些基本的功能都已經做的很完善了,海量資料處理成為重點的問題,也是面試筆試中常考的題目。主要參考 1.分而治之 hash對映 hash統計 堆 快速 歸併排序 hash對映很重要,分類後的資料不會分散,某乙個類別的資料會全部在一起。用hash map統計的速度要比ma...