解題筆記(9) 提取某日訪問次數最多的那個IP

2021-05-26 21:06:14 字數 2734 閱讀 9536

問題描述:從海量資料日誌中,提取出某日訪問次數最多的那個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...