编程之法之海量数据处理:寻找Top K的热词
Posted xiaoranone
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编程之法之海量数据处理:寻找Top K的热词相关的知识,希望对你有一定的参考价值。
题目:
有100万个关键字,长度小于50个字节。用有效的算法找出Top 10的热词,要求对内存的占用不超过1 MB。
分析:
这是大家面试中都被问道的问题,可以直接使用map-reducer直接解决这个问题。如果不能使用这个架构,我们手动实现,也是采用的这个思想,只是这个用文件代替节点。
1
0
6
∗
50
B
=
50
∗
1
0
6
B
=
50
M
B
10^6 * 50B = 50 * 10^6B = 50MB
106∗50B=50∗106B=50MB
因为要求最多1MB内存,我们需要划分成50个小文件。划分的时候我们需要保证所有相同的字符串在同一个文件中,这样我们就可以单独统计每一个小文件,最后合并结果即可。当然这个文件大家都已经理解了,这里主要是从C++的代码进行实现。
首先我们明确需要几个函数:
-
划分函数,将相同的字符串划分到相同小文件中, 这里我们需要有一个hash函数,将每个字符串映射成整数,再对小文件个数(50)取余。
-
统计每个小文件中的热词,这里需要实现一个统计函数,我们可以基于最小堆进行实现。
-
合并所有小文件的结果的函数,合并函数。
-
由于我们没有数据,需要写一个随机函数,生出数据,生出数据的函数。
-
随机产生数据的函数
/** 随机产生200W个长度为10的字符串,写入文件中,字符[0-5] + 'a'*/
void randCreateData(const char* outputfile, const int cnt = 1000000)
FILE *fp = NULL;
fp = fopen(outputfile, "w+");
if(fp == NULL)
printf("File error\\n");
return;
srand((unsigned)time(0));
for(int i = 0; i < cnt; i++)
char tmp[12];
int j;
for(j = 0; j < 5; j++)
tmp[j] = char(rand()%5 + 'a');
tmp[j] = '\\0';
fprintf(fp, "%s\\n", tmp);
fclose(fp);
- hash key函数
/** 得到hash(str) % MOD **/
int hash_key(const char* str)
int value = 0;
while(*str != '\\0')
value = value * 31 + *str;
value = value % MOD;
str ++;
return value;;
- 分割函数
/** 将200w * 5B的文件,根据key划分成50个文件,每个文件100B,大约1M **/
void partation(const char* inputfile, int filecnt = 50)
FILE * fps[filecnt];
for(int i = 0; i < filecnt; i++)
char tmpfile[20] = "./data/tmpfile";
char s[3];
sprintf(s, "%d", i);
char *file = strcat(tmpfile, s);
// printf("%s\\n", file);
fps[i] = fopen(file, "w+");
assert(fps[i] != NULL);
FILE *fp_read = fopen(inputfile, "r");
assert(fp_read != NULL);
int i = 0;
char buffer[10];
while(! feof(fp_read))
// 这样读取包含换行符
fgets(buffer, sizeof(buffer)-1 ,fp_read);
// 去掉换行符号
buffer[strlen(buffer)-1] = '\\0';
// 得到字符串对应的key,写入对应的文件
int key = hash_key(buffer) % filecnt;
fprintf(fps[key], "%s\\n", buffer);
// close 所有文件指针
for(int i = 0; i < filecnt; i++)
fclose(fps[i]);
fclose(fp_read);
- 处理一个文件的函数
/** 统计单个文件中的出现的频率 **/
int preocessedOneFile(const char *inputfile, const int topK=100)
map<string, int> s2cnt;
FILE *fp_read = fopen(inputfile, "r");
assert(fp_read != NULL);
int i = 0;
char buffer[10];
while(! feof(fp_read))
// 这样读取包含换行符
fgets(buffer, sizeof(buffer)-1 ,fp_read);
// 去掉换行符号
buffer[strlen(buffer)-1] = '\\0';
string s = buffer;
s2cnt[s] += 1;
// cout<<s2cnt.size()<<endl;
for(auto it=s2cnt.begin(); it!=s2cnt.end(); it++)
q.push(make_pair(it->first, it->second));
if(q.size() > topK) // 保存最大的100个
q.pop();
/*
int k = 0;
while(q.size())
pair<string, int> t = q.top();
cout<<t.first<<" "<<t.second<<endl;
q.pop();
k ++;
if(k > 10) break;
*/
return s2cnt.size();
全部源码:github 源码
以上是关于编程之法之海量数据处理:寻找Top K的热词的主要内容,如果未能解决你的问题,请参考以下文章