提取出某日访问百度次数最多的IP

来源:互联网 发布:手机端时时彩源码 编辑:程序博客网 时间:2024/05/24 15:36
 

提取出某日访问百度次数最多的IP

分类: 算法 1060人阅读 评论(2) 收藏 举报
百度iospathinidelete测试

问题描述:海量日志数据,提取出某日访问百度次数最多的那个IP。

方法1: 计数法

    假设一天之内某个IP访问百度的次数不超过40亿次,则访问次数可以用unsigned表示.用数组统计出每个IP地址出现的次数,  即可得到访问次数最大的IP地址.

    IP地址是32位的二进制数,所以共有N=2^32=4G个不同的IP地址, 创建一个unsigned count[N];的数组,即可统计出每个IP的访问次数,而sizeof(count) == 4G*4=16G, 远远超过了32位计算机所支持的内存大小,因此不能直接创建这个数组.下面采用划分法解决这个问题.

    假设允许使用的内存是512M,  512M/4=128M 即512M内存可以统计128M个不同的IP地址的访问次数.而N/128M =4G/128M = 32 ,所以只要把IP地址划分成32个不同的区间,分别统计出每个区间中访问次数最大的IP, 然后就可以计算出所有IP地址中访问次数最大的IP了.

    因为2^5=32, 所以可以把IP地址的最高5位作为区间编号, 剩下的27为作为区间内的值,建立32个临时文件,代表32个区间,把相同区间的IP地址保存到同一的临时文件中.

例如:

ip1=0x1f4e2342

ip1的高5位是id1  =  ip1 >>27 = 0x11 = 3

ip1的其余27位是value1  =  ip1 &0x07ffffff = 0x074e2342

所以把 value1 保存在tmp3文件中.

由id1和value1可以还原成ip1, 即 ip1 =(id1<<27)|value1

    按照上面的方法可以得到32个临时文件,每个临时文件中的IP地址的取值范围属于[0-128M),因此可以统计出每个IP地址的访问次数.从而找到访问次数最大的IP地址

程序源码:

test.cpp是c++源码.

  1. #include <fstream>  
  2. #include <iostream>  
  3. #include <ctime>  
  4.   
  5. using namespace std;  
  6. #define N 32           //临时文件数  
  7.   
  8. #define ID(x)  (x>>27)                 //x对应的文件编号  
  9. #define VALUE(x) (x&0x07ffffff)        //x在文件中保存的值  
  10. #define MAKE_IP(x,y)  ((x<<27)|y)      //由文件编号和值得到IP地址.  
  11.   
  12. #define MEM_SIZE  128*1024*1024       //需分配内存的大小为 MEM_SIZE*sizeof(unsigned)     
  13.   
  14. char* data_path="D:/test/ip.dat";        //ip数据  
  15.   
  16.  //产生n个随机IP地址  
  17. void make_data(const int& n)         
  18. {  
  19.     ofstream out(data_path,ios::out|ios::binary);  
  20.     srand((unsigned)(time(NULL)));  
  21.     if (out)  
  22.     {  
  23.         for (int i=0; i<n; ++i)  
  24.         {  
  25.             unsigned val=unsigned(rand());           
  26.             val = (val<<24)|val;              //产生unsigned类型的随机数  
  27.   
  28.             out.write((char *)&val,sizeof (unsigned));  
  29.         }  
  30.     }  
  31. }  
  32.   
  33. //找到访问次数最大的ip地址  
  34. int main()  
  35. {  
  36.     //make_data(100);     //   
  37.     make_data(100000000);       //产生测试用的IP数据  
  38.     fstream arr[N];  
  39.       
  40.     for (int i=0; i<N; ++i)                 //创建N个临时文件  
  41.     {  
  42.         char tmp_path[128];     //临时文件路径  
  43.         sprintf(tmp_path,"D:/test/tmp%d.dat",i);  
  44.         arr[i].open(tmp_path, ios::trunc|ios::in|ios::out|ios::binary);  //打开第i个文件  
  45.   
  46.         if( !arr[i])  
  47.         {  
  48.             cout<<"open file"<<i<<"error"<<endl;  
  49.         }  
  50.     }  
  51.   
  52.     ifstream infile(data_path,ios::in|ios::binary);   //读入测试用的IP数据  
  53.     unsigned data;  
  54.   
  55.     while(infile.read((char*)(&data), sizeof(data)))  
  56.     {  
  57.         unsigned val=VALUE(data);  
  58.         int key=ID(data);  
  59.         arr[ID(data)].write((char*)(&val), sizeof(val));           //保存到临时文件件中  
  60.     }  
  61.   
  62.     for(unsigned i=0; i<N; ++i)  
  63.     {  
  64.         arr[i].seekg(0);  
  65.     }  
  66.     unsigned max_ip = 0;    //出现次数最多的ip地址  
  67.     unsigned max_times = 0;     //最大只出现的次数  
  68.   
  69.     //分配512M内存,用于统计每个数出现的次数  
  70.     unsigned *count = new unsigned[MEM_SIZE];    
  71.   
  72.     for (unsigned i=0; i<N; ++i)  
  73.     {  
  74.         memset(count, 0, sizeof(unsigned)*MEM_SIZE);  
  75.   
  76.         //统计每个临时文件件中不同数字出现的次数  
  77.         unsigned data;  
  78.         while(arr[i].read((char*)(&data), sizeof(unsigned)))       
  79.         {  
  80.             ++count[data];  
  81.         }  
  82.           
  83.         //找出出现次数最多的IP地址  
  84.         for(unsigned j=0; j<MEM_SIZE; ++j)                             
  85.         {  
  86.             if(max_times<count[j])             
  87.             {  
  88.                 max_times = count[j];  
  89.                 max_ip = MAKE_IP(i,j);        // 恢复成原ip地址.  
  90.             }  
  91.         }  
  92.     }  
  93.     delete[] count;  
  94.     unsigned char *result=(unsigned char *)(&max_ip);  
  95.     printf("出现次数最多的IP为:%d.%d.%d.%d,共出现%d次",   
  96.         result[0], result[1], result[2], result[3], max_times);  
  97. }  

执行结果.

转自http://blog.csdn.net/v_july_v/article/details/6712171

方法2::分而治之+Hash
1.IP地址最多有2^32=4G种取值情况,所以不能完全加载到内存中处理;  
2.可以考虑采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件最多包含4MB个IP地址;  
3.对于每一个小文件,可以构建一个IP为key,出现次数为value的Hash map,同时记录当前出现次数最多的那个IP地址;
4.可以得到1024个小文件中的出现次数最多的IP,再依据常规的排序算法得到总体上出现次数最多的IP;

0 0