您的位置:首页 > 其它

海量数据处理问题。。。

2016-09-16 19:45 267 查看

蓄水池抽样算法

在不知道文件总行数的情况下,如何从文件中随机的抽取一行?

给你一个长度为N的链表。N很大,但你不知道N有多大。你的任务是从这N个元素中随机取出k个元素。你只能遍历这个链表一次。你的算法必须保证取出的元素恰好有k个,且它们是完全随机的(出现概率均等)?

top k问题

YoferZhang

http://blog.csdn.net/zyq522376829/article/details/47686867

july 教你如何迅速秒杀99%的海量数据处理面试题

http://www.cnblogs.com/v-July-v/archive/2012/03/22/2413055.html

leetcode

347. Top K Frequent Elements

题目地址

https://leetcode.com/problems/top-k-frequent-elements/

普通的map,加上堆结构(priority_queue)

ac代码:

struct cmp
{
bool operator()(pair<int, int> p1, pair<int, int> p2){
return p1.second < p2.second;
}

};

class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> ans;

unordered_map<int, int> mp;

int len = nums.size();
for (int i = 0; i < len; i++)
{
mp[nums[i]] = mp[nums[i]] + 1;
}

priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> pq;

unordered_map<int, int>::iterator it = mp.begin();
while (it != mp.end()){
pq.push(pair<int, int>{it->first, it->second});
++ it;
}

while (k-- && !pq.empty()){
pair<int, int> tmp = pq.top();
pq.pop();
ans.push_back(tmp.first);
}

return ans;
}
};


基于海量数据的查找 ,统计, 运算等操作。所谓海量数据,就是数据量太大,所以导致要么无法再较短时间内迅速解决,要么是数据太大,导致无法一次性装入内存。从而导致传统的操作无法实现。

分治 + Hash映射

对大文件处理是,若文件过大,无法一次性读入内存,可以考虑采取Hash映射的方法将文件中的元素映射到不同的小文件,然后处理小文件的结构,最后合并处理结果,这样就降低了问题的规模。

例题 1: 给定a,b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4GB,请你找出a,b文件共同的url.

5GB * 64 = 320 GB,远大于内存限制的4GB,不能一次性的加载到内存中

对文件a,对每个url求取 hash(url) % 1024,分配到1024个小文件中,在这样每个文件约300MB

对文件b,采取同样的做法。这样之后,所有可能相同的url都在对应的小文件(a0 b0)(a1 b1) … 等中,不对应的小文件不可能有相同的url, 这样只要求出1024个对应小文件相同的url.

求每对小文件中相同的url时,可以把其中的一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url

例题 2: 有10个文件,每个文件1GB,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。

1

顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件中,记为a0,a1,…,a9,这样新生成的文件每个大小约为1GB;

找一台内存在2GB左右的机器,依次对a0,a1,…,a9用hash_map(query,query_count)来统计每个query出现的次数,并利用快速、堆、归并排序按照出现次数进行排序。将排序好的query和对应的query_count输出到文件中。这样得到了10个排好序的文件,记为b0,b1,…,b9这10个文件进行归并排序(可利用败者树进行多路归并)。

2

一般query的总量是有限的,只是重复的次数比较多,若所有的query一次性就可以加入到内存中,就可以采用Trie树 / hash_map等直接统计每个query出现的次数, 然后按出现次数做快速、堆、归并排序就可以了。

top K

堆也是海量数据处理经常采用的工具

例题1 : 有一个1GB大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1MB。返回频数最高的100个词、

分治法。顺序读文件,对于每个词x,取hash(x) % 5000,然后按照该值存到5000个小文件中,记为x0, x1, … , x4999。这样每个文件为200KB左右。如果其中的有的文件超过1MB,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1MB.对每个小文件,统计每个文件中出现的词以及相应的频率(可以采用Trie数或hash_map等),并分别取出出现频率最大的100个词(可以用含100个节点的最小堆),并把这100个词以及相应的频率存入文件,这样又得到了5000个有序(逆序)文件(每个文件有100个词)。下一步就是把这5000个文件进行归并排序(可利用败者树采用多路归并)的过程了。

例题2 : 海量日志数据,提取出某日访问百度次数最多的那个IP,假设当前机器可用内存较小,无法一次性读入日志文件。

使用分治思想。

因为内存中不能存放所有的数据,为了保证将海量数据分成几个小块后,每个小块中的元素都互不相同,也就是值相同的元素要分到同一个数据块中,可以使用hash的方法,hash(value)%n, n就是要分的块数,这样再每个小块中在使用hash_map的方法统计每个value的频度,在利用堆排序对每个小块的频度进行排序。具体处理过程如下:

IP地址最多有2^32=4GB种取值可能,按照IP地址的hash(IP)%1024值,将海量日志存储到1024个小文件中。每个小文件最多包含4MB个IP地址。

对于每个小文件,可以构建一个IP作为key,出现次数作为value的hash_map,并记录当前出现次数最多的1个IP地址。

有了1024个小文件中的出现次数最多的IP,我们就可以轻松得到总体上出现的最多的IP。

bit-map

bit-map的原理就是使用位数组表示某些元素是否存在,由于采用了bit为单位来存储数据,因此在存储空间方面,可以大大节省,故适用于海量数据的快速查找,判重,删除等。



在程序设计中,经常需要判断集合中是否存在重复的问题,当数据量比较大是,位图法比较合适。

例题:已知某个文件内包含一些电话号码,每个号码为8为数字,统计不同号码的个数。

8位数字表示的最大数为999999999(0-99999999的数字),用bit-map解决,则每个数字对应一个bit位,所以只需要约12MB,这样,就用了只有12M左右的内存表示了所有的8位数的电话,一次读入每个电话号码,然后bitmap相应位置为1,最后统计bit-map中1的位数,即为不同的号码个数

位图法还可以用来快速判断集合中某个数据是否存在

例题 : 给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在40亿个不重复的数中

unsigned int 最多有232个数,bitmap 申请 232(512 * 2^20*8) 512M的内存

例题 : 2.5亿个整数中,找出只出现一次的整数,内存不能容纳这2.5一个数

1 bitmap

每个数2bit 00 表示不存在,01表示只出现一次,10表示出现多次

分治 + hash映射

分成小文件,利用hash_map找不重复的整数

布隆过滤器

布隆过滤器是一种多哈希函数映射的快速查找算法。它可以判断出某个元素肯定不在集合里或者可能在集合里,即它不会漏报,但可能会误报。通常应用在一些需要快速判断某个元素是否属于集合,但不严格要求100%正确的场合。



参考

http://www.cnblogs.com/Jack47/p/bloom_filter_intro.html

倒排索引



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: