問題描述:從海量資料日誌中,提取出某日訪問次數最多的那個ip。
思路:對於海量資料的處理,主要採取的策略就是分而治之,即縮減問題的規模,將乙個大的問題劃分成若干等價的小問題。然後解決這些小問題,最後將獲得的小問題解綜合起來,得出原問題的解。用到比較多的技術主要有雜湊、位圖、堆、trie樹、mapreduce、k路歸併(敗者樹)等。其中雜湊用的尤為多。
對於本問題,假定某日訪問的ip位址已經從資料日誌中提取出來,存放在乙個大的二進位制檔案中。下面的工作主要是找目標ip——檔案中出現次數最多的那個ip。這個檔案很大,記憶體無法完全放下,內排序的方法行不通。可以採取如下措施:
(1)利用雜湊函式,將大檔案中的ip位址雜湊到若干個檔案中。相同的ip位址肯定在同乙個檔案中。
(2)處理每個小檔案,找到該檔案中出現次數最多的那個ip,記錄下ip位址和出現次數。可以用hash_map,ip位址為鍵值、出現次數為數值。
(3)將第(2)步中找到的ip位址及出現次數綜合起來,找到這些ip位址中出現次數最多的那個ip。
簡單實現:接下來給出一種簡單的實現,效率比較低。測試中,從乙個含4億個ip位址的檔案中提取目標ip,一共用了52分鐘。其中大量的時間用於檔案的讀寫,約為30分鐘。另外有7分鐘用於產生含4億個隨機數的檔案。真正用於計算的時間為15分鐘。由於c++標準stl中沒有hash_map,因此該用map實現第(2)步,如果改用hash_map,應該能減少部分計算的時間。
另外,如果設定讀寫緩衝區,經過測試,緩衝區為128位元組時,讀寫檔案的時間從原來的30分鐘減為25分鐘左右。進一步增大緩衝區大小,提公升的速度比非常小,待求解。這裡設定緩衝區不是指這種方式:
char buffer[1024];
streambuf * ptrbuf = outfile.rdbuf();
ptrbuf-> pubsetbuf(buffer,1024);
而是定義乙個整形陣列,每次讀寫時,讀寫一塊資料而不是乙個整數。
單個讀寫 outfile.write((char*)&x,sizeof(unsigned));
塊讀寫 outfile.write((char *)buffer,buffer_size*sizeof(unsigned));
vc6.0下編譯執行通過
#pragma warning(disable:4786) 中 忽略警告
#include #include #include #include #include using namespace std;
const unsigned n=400000000; //隨機產生的ip位址數
const unsigned file_num=16; //產生的小檔案個數
const unsigned hash_shift=28; //雜湊值的位移量
inline unsigned hashint(unsigned value); //將整數雜湊到0到file_num之間
bool produceip(string filename); //隨機產生ip位址,看成是32位無符號數
bool decomposefile(string filename); //分而治之,將大檔案分為若干個小檔案
bool findtargetip(unsigned result[2]); //找到出現次數最多的ip
int main()
; //儲存結果
start=clock();
start1=clock();
//隨機產生大量ip
if(produceip(name)==false)
return 1;
end1=clock();
start2=clock();
//分而治之
if(decomposefile(name)==false)
return 1;
end2=clock();
start3=clock();
//找到出現次數最多的ip
if(findtargetip(result)==false)
return 1;
end3=clock();
end=clock();
//列印結果
cout<<"total run time : "<<(end-start)/1000.0<>24)<<'.'<<((result[0]&0x00ff0000)>>16)<<'.';
cout<<((result[0]&0x0000ff00)>>8)<<'.'<<((result[0]&0x000000ff))<> s;
//value是16位整數,m = 40503
//value是32位整數,m = 2654435769
//value是64位整數,m = 11400714819323198485
//s與桶的個數有數,如果桶的個數為16,那麼s為28
//對於32位整數,s=32-log2(桶的個數)
return (value*2654435769)>>hash_shift;
}//隨機產生ip位址 看成是32位無符號數
bool produceip(string filename)
} map::iterator it=ip_count.begin();
for(;it!=ip_count.end();it++)
}infile.close();
} return true;
}
提取出某日訪問百度次數最多的那個IP
方法 計數法 ip位址是32位的二進位制數,所以共有n 2 32 4g個不同的ip位址,建立乙個unsigned count n 的陣列,即可統計出每個ip的訪問次數,而sizeof count 4g 4 16g,遠遠超過了32位計算機所支援的記憶體大小,因此不能直接建立這個陣列.下面採用劃分法解決...
海量日誌提取訪問次數最多的
方法 計數法 ip位址是32位的二進位制數,所以共有n 2 32 4g個不同的ip位址,建立乙個unsigned count n 的陣列,即可統計出每個ip的訪問次數,而sizeof count 4g 4 16g,遠遠超過了32位計算機所支援的記憶體大小,因此不能直接建立這個陣列.下面採用劃分法解決...
SHELL 分析 列出當天訪問次數最多的IP
shell 分析日誌 lvtao 發布於 2013 7 3 14 58 wednesday 分類 工具原始碼 列出當天訪問次數最多的ip 命令 cut d f 1 usr local apache2 logs access log uniq c sort rn head 20 原理 cut d,de...