模拟大数据处理、linux下hash_map()使用

来源:互联网 发布:mac win10 iso 下载 编辑:程序博客网 时间:2024/05/16 19:54

写一个程序模拟大数据处理方法。

模拟情景:访问日志里有100万条ip,每条ip占一行。现在要求访问次数最高的前3个ip(后面称作top3)。(假设我们的内存不足以同时处理100万条ip)。

处理方法:逐条处理100万条ip中的每一条ip,根据hash值将ip写入到不同的小文件中(相同hashcode的ip写入同一个小文件中),对每个小文件用hash_map统计每一条ip出现的次数,然后针对每一个小文件求top3(小文件个数设置应使内存足以处理每一个小文件),将每个小文件对应的top3写入对应的统计文件(一个统计文件对应一个小文件)中,最后在所有统计文件中求整体的top3。

求top3时用的方法是:用前三个元素建一个三个元素的小根堆,然后依次遍历剩下的元素,当一个元素出现的次数大于小根堆堆顶元素出现次数时,用这个元素替换堆顶元素,然后对堆顶元素进行一次向下筛选。知道所有元素遍历完,此时的小根堆就是出现次数最多的top3。

 

我所用的变成环境是:linux,gnu编译器,在此环境下使用hash_map时遇到一个问题:gnu的hash_map不能以std::string类型作为键类型,原因是gnu版编译器没有定义求std::string的hashcode的函数,解决方法是自己定义一个对std::string类型求hashcode的类。gnu版编译器提供的hash_map可以以char*作为键类型,但需要自己定义char*代表的字符串比较类模板(否则hash_map在进行关键字比较时,比较的是指针,而不是字符串),另外,以char*作为键类型时,hash_map是处理的char*变量指向的字符串(hash_map只记住了char*变量,并没有记住字符串),所以为了表示不同的字符串,必须分配空间大量字符串空间已存放不同的字符串(假如用同一个char[]存放每次读取的字符串,虽然每个字符串的hashcode不同,但因为改变了hash表中某一个元素的键的内容(这些键会在iterator++操作时用到:iterator++操作根据当前元素的键算出下一个应该遍历的元素在hash表中的位置,具体做法是:计算当前元素的键的hashcode,根据hashcode就知道这个元素在hash表中的第几个桶中(桶号),找下一个元素时,若当前同的元素已遍历完,那么就需要当前桶号的后面一个桶的号(当前桶号加1),所以若用同一个字符数组存储字符串,做++操作时用来计算hashcode的字符串的内容与插入那个字符串时的内容不同(这样两次计算的hashcode就不相同,也就是查找时计算出来的hashcode不再是当前元素所在的桶的桶号),这就会引起异常结果),使得在进行++操作时差生异常结果,可能导致死循环。),耗费空间较大。

 

下面分别针对std::string类型作为键类型和char*作为键类型两种情况提供代码。

1、以char*作为键类型

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<iostream>#include<boost/functional/hash.hpp>#include<string>#include<ext/hash_map>using namespace __gnu_cxx;void create_original_file()            //生成一个初试大文件{    FILE* original_file_pointer=fopen("./original_file","w");    char str_ip[16];    int rand_number;    char str_random[5];    srand(0);    for(int i=0;i<1000000;i++)    {        strcpy(str_ip,"192.168.");        rand_number=(int)(255*(rand()/(RAND_MAX+1.0)));        sprintf(str_random,"%d",rand_number);        strcat(str_ip,str_random);        strcat(str_ip,".");        rand_number=(int)(255*(rand()/(RAND_MAX+1.0)));        sprintf(str_random,"%d",rand_number);        strcat(str_ip,str_random);        if(i<999999)            fprintf(original_file_pointer,"%s\n",str_ip);        else            fprintf(original_file_pointer,"%s",str_ip);    }    fclose(original_file_pointer);}void divide_file()    //把初试大文件分割1000个小文件{    boost::hash<std::string> ip_hash;    std::size_t ip_hash_code;    FILE* small_files[1000];    for(int i=0;i<1000;i++)    {        char th[30]="./smallfiles/small_file_";        sprintf(th+24,"%d",i);        small_files[i]=fopen(th,"w");    }    FILE* original_file_pointer=fopen("./original_file","r");    char str_ip[16];    std::string string_ip;    for(int i=0;i<1000000;i++)    {        fscanf(original_file_pointer,"%s",str_ip);        string_ip=str_ip;        ip_hash_code=ip_hash(string_ip);        fprintf(small_files[ip_hash_code%1000],"%s\n",str_ip);    }    fclose(original_file_pointer);    for(int i=0;i<1000;i++)    {        fclose(small_files[i]);    }}struct ip_counter_struct        //ip以及其对应的counter的结构体{    std::string struct_string_ip;    int struct_counter;};void sift_down(ip_counter_struct struct_map[],int position,int length)    //堆的一次向下筛选{    int j=2*position+1;    while(j<length)    {        if(((j+1)<length)&&(struct_map[j+1].struct_counter<struct_map[j].struct_counter))            j=j+1;        if(struct_map[position].struct_counter>struct_map[j].struct_counter)        {            std::swap(struct_map[position],struct_map[j]);            position=j;            j=2*position+1;        }        else            break;    }}void create_heap(ip_counter_struct struct_map[],int length)    //建堆{    int i=(length-2)/2;    while(i>0)    {        sift_down(struct_map,i,length);        i=(i-1)/2;    }    sift_down(struct_map,0,length);}struct eqstr     //hash_map用来比较char*表示的字符串时所用的类{    bool operator()(const char* s1,const char* s2) const    {        return strcmp(s1,s2)==0;    }};void statistic()     //统计每个ip出现的次数,并把每个小文件对应的top3写入对应的统计文件{    ip_counter_struct ip_counter_s[3];    for(int i=0;i<3;i++)    {        ip_counter_s[i].struct_counter=0;    }    char str_ip[10000][16];    for(int i=0;i<1000;i++)    {        hash_map<const char*,int,hash<const char*>,eqstr> ip_counter;        char th[30]="./smallfiles/small_file_";        char statistic_th[35]="./statistic/statistic_file_";        sprintf(th+24,"%d",i);        sprintf(statistic_th+27,"%d",i);        FILE* small_file_pointer=fopen(th,"r");        FILE* statistic_file_pointer=fopen(statistic_th,"w");        int j=0;        for(;fscanf(small_file_pointer,"%s",str_ip[j])!=EOF;)        {            ip_counter[str_ip[j]]=ip_counter[str_ip[j]]+1;            j++;        }        fclose(small_file_pointer);        hash_map<const char*,int,hash<const char*>,eqstr>::iterator hash_map_it=ip_counter.begin();        int number;        for(number=0;number<3;number++)        {            if(hash_map_it!=ip_counter.end())            {                ip_counter_s[number].struct_string_ip=hash_map_it->first;                ip_counter_s[number].struct_counter=hash_map_it->second;                ++hash_map_it;            }            else                break;        }        switch(number)        {            case 0:                break;            case 1:                fprintf(statistic_file_pointer,"%s ",ip_counter_s[0].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d",ip_counter_s[0].struct_counter);                break;            case 2:                fprintf(statistic_file_pointer,"%s ",ip_counter_s[0].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d\n",ip_counter_s[0].struct_counter);                fprintf(statistic_file_pointer,"%s ",ip_counter_s[1].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d\n",ip_counter_s[1].struct_counter);                break;            case 3:                create_heap(ip_counter_s,3);                while(hash_map_it!=ip_counter.end())                {                    if(hash_map_it->second>ip_counter_s[0].struct_counter)                    {                        ip_counter_s[0].struct_string_ip=hash_map_it->first;                        ip_counter_s[0].struct_counter=hash_map_it->second;                        sift_down(ip_counter_s,0,3);                    }                    ++hash_map_it;                }                for(int i=0;i<3;i++)                {                    fprintf(statistic_file_pointer,"%s ",ip_counter_s[i].struct_string_ip.c_str());                    fprintf(statistic_file_pointer,"%d\n",ip_counter_s[i].struct_counter);                }                break;            defualt:break;        }        fclose(statistic_file_pointer);    }}void get_total_top_k()         //得到整体的top3{    ip_counter_struct ip_counter_s[3];    for(int i=0;i<3;i++)    {        ip_counter_s[i].struct_counter=0;    }    int number=0;    char str_ip[16]="";    int counter=0;    for(int i=0;i<1000;i++)    {        char statistic_th[35]="./statistic/statistic_file_";        sprintf(statistic_th+27,"%d",i);        FILE* statistic_file_pointer=fopen(statistic_th,"r");        while(fscanf(statistic_file_pointer,"%s",str_ip)!=EOF)        {            fscanf(statistic_file_pointer,"%d",&counter);            if(number<2)            {                ip_counter_s[number].struct_string_ip=str_ip;                ip_counter_s[number].struct_counter=counter;                number++;            }            else if(number==2)            {                ip_counter_s[number].struct_string_ip=str_ip;                ip_counter_s[number].struct_counter=counter;                number++;                create_heap(ip_counter_s,3);            }            else            {                if(counter>ip_counter_s[0].struct_counter)                {                    ip_counter_s[0].struct_string_ip=str_ip;                    ip_counter_s[0].struct_counter=counter;                    sift_down(ip_counter_s,0,3);                }                number++;            }        }        fclose(statistic_file_pointer);    }    for(int i=0;i<3;i++)        std::cout<<ip_counter_s[i].struct_string_ip<<" "<<ip_counter_s[i].struct_counter<<std::endl;}int main(){    create_original_file();    divide_file();    statistic();    get_total_top_k();    return 0;}


2、std::string作为键类型

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<iostream>#include<boost/functional/hash.hpp>#include<string>#include<ext/hash_map>using namespace __gnu_cxx;namespace __gnu_cxx{    template<> struct hash<std::string>      //定义计算std::string的hashcode的类    {        std::size_t operator()(const std::string &s) const        {            boost::hash<std::string> string_hash;            return string_hash(s);        }    };}void create_original_file(){    FILE* original_file_pointer=fopen("./original_file","w");    char str_ip[16];    int rand_number;    char str_random[5];    srand(0);    for(int i=0;i<1000000;i++)    {        strcpy(str_ip,"192.168.");        rand_number=(int)(255*(rand()/(RAND_MAX+1.0)));        sprintf(str_random,"%d",rand_number);        strcat(str_ip,str_random);        strcat(str_ip,".");        rand_number=(int)(255*(rand()/(RAND_MAX+1.0)));        sprintf(str_random,"%d",rand_number);        strcat(str_ip,str_random);        if(i<999999)            fprintf(original_file_pointer,"%s\n",str_ip);        else            fprintf(original_file_pointer,"%s",str_ip);    }    fclose(original_file_pointer);}void divide_file(){    boost::hash<std::string> ip_hash;    std::size_t ip_hash_code;    FILE* small_files[1000];    for(int i=0;i<1000;i++)    {        char th[30]="./smallfiles/small_file_";        sprintf(th+24,"%d",i);        small_files[i]=fopen(th,"w");    }    FILE* original_file_pointer=fopen("./original_file","r");    char str_ip[16];    std::string string_ip;    for(int i=0;i<1000000;i++)    {        fscanf(original_file_pointer,"%s",str_ip);        string_ip=str_ip;        ip_hash_code=ip_hash(string_ip);        fprintf(small_files[ip_hash_code%1000],"%s\n",str_ip);    }    fclose(original_file_pointer);    for(int i=0;i<1000;i++)    {        fclose(small_files[i]);    }}struct ip_counter_struct{    std::string struct_string_ip;    int struct_counter;};void sift_down(ip_counter_struct struct_map[],int position,int length){    int j=2*position+1;    while(j<length)    {        if(((j+1)<length)&&(struct_map[j+1].struct_counter<struct_map[j].struct_counter))            j=j+1;        if(struct_map[position].struct_counter>struct_map[j].struct_counter)        {            std::swap(struct_map[position],struct_map[j]);            position=j;            j=2*position+1;        }        else            break;    }}void create_heap(ip_counter_struct struct_map[],int length){    int i=(length-2)/2;    while(i>0)    {        sift_down(struct_map,i,length);        i=(i-1)/2;    }    sift_down(struct_map,0,length);}void statistic(){    ip_counter_struct ip_counter_s[3];    for(int i=0;i<3;i++)    {        ip_counter_s[i].struct_counter=0;    }    char str_ip[16]="";    std::string string_ip;    for(int i=0;i<1000;i++)    {        hash_map<std::string,int> ip_counter;        char th[30]="./smallfiles/small_file_";        char statistic_th[35]="./statistic/statistic_file_";        sprintf(th+24,"%d",i);        sprintf(statistic_th+27,"%d",i);        FILE* small_file_pointer=fopen(th,"r");        FILE* statistic_file_pointer=fopen(statistic_th,"w");        for(;fscanf(small_file_pointer,"%s",str_ip)!=EOF;)        {            string_ip=str_ip;            ip_counter[string_ip]=ip_counter[string_ip]+1;        }        fclose(small_file_pointer);        hash_map<std::string,int>::iterator hash_map_it=ip_counter.begin();        int number;        for(number=0;number<3;number++)        {            if(hash_map_it!=ip_counter.end())            {                ip_counter_s[number].struct_string_ip=hash_map_it->first;                ip_counter_s[number].struct_counter=hash_map_it->second;                ++hash_map_it;            }            else                break;        }        switch(number)        {            case 0:                break;            case 1:                fprintf(statistic_file_pointer,"%s ",ip_counter_s[0].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d",ip_counter_s[0].struct_counter);                break;            case 2:                fprintf(statistic_file_pointer,"%s ",ip_counter_s[0].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d\n",ip_counter_s[0].struct_counter);                fprintf(statistic_file_pointer,"%s ",ip_counter_s[1].struct_string_ip.c_str());                fprintf(statistic_file_pointer,"%d\n",ip_counter_s[1].struct_counter);                break;            case 3:                create_heap(ip_counter_s,3);                while(hash_map_it!=ip_counter.end())                {                    if(hash_map_it->second>ip_counter_s[0].struct_counter)                    {                        ip_counter_s[0].struct_string_ip=hash_map_it->first;                        ip_counter_s[0].struct_counter=hash_map_it->second;                        sift_down(ip_counter_s,0,3);                    }                    ++hash_map_it;                }                for(int i=0;i<3;i++)                {                    fprintf(statistic_file_pointer,"%s ",ip_counter_s[i].struct_string_ip.c_str());                    fprintf(statistic_file_pointer,"%d\n",ip_counter_s[i].struct_counter);                }                break;            defualt:break;        }        fclose(statistic_file_pointer);    }}void get_total_top_k(){    ip_counter_struct ip_counter_s[3];    for(int i=0;i<3;i++)    {        ip_counter_s[i].struct_counter=0;    }    int number=0;    char str_ip[16]="";    int counter=0;    for(int i=0;i<1000;i++)    {        char statistic_th[35]="./statistic/statistic_file_";        sprintf(statistic_th+27,"%d",i);        FILE* statistic_file_pointer=fopen(statistic_th,"r");        while(fscanf(statistic_file_pointer,"%s",str_ip)!=EOF)        {            fscanf(statistic_file_pointer,"%d",&counter);            if(number<2)            {                ip_counter_s[number].struct_string_ip=str_ip;                ip_counter_s[number].struct_counter=counter;                number++;            }            else if(number==2)            {                ip_counter_s[number].struct_string_ip=str_ip;                ip_counter_s[number].struct_counter=counter;                number++;                create_heap(ip_counter_s,3);            }            else            {                if(counter>ip_counter_s[0].struct_counter)                {                    ip_counter_s[0].struct_string_ip=str_ip;                    ip_counter_s[0].struct_counter=counter;                    sift_down(ip_counter_s,0,3);                }                number++;            }        }        fclose(statistic_file_pointer);    }    for(int i=0;i<3;i++)        std::cout<<ip_counter_s[i].struct_string_ip<<" "<<ip_counter_s[i].struct_counter<<std::endl;}int main(){    create_original_file();    divide_file();    statistic();    get_total_top_k();    return 0;}


 

原创粉丝点击