海量数据问题全集

来源:互联网 发布:大数据战略 编辑:程序博客网 时间:2024/06/05 21:03

教你如何迅速秒杀掉:99%的海量数据处理面试题:http://blog.csdn.net/v_july_v/article/details/7382693

十道海量数据处理面试题与十个方法大总结:http://blog.csdn.net/v_JULY_v/article/details/6279498

1,海量数据处理的一般办法

1,分而治之/hash映射 + hash统计 + 堆/快速/归并排序;
2,双层桶划分
3,Bloom filter/Bitmap;
4,Trie树/数据库/倒排索引;
5,外排序;
6,分布式处理之Hadoop/Mapreduce。

2,一般数据结构

2.1 基于RB-tree(有自动排序功能)

http://blog.csdn.net/v_july_v/article/category/774945

1,set  

(value)

2,multiset

3,map 

(key,value)

4,multimap

2.2 基于hashtable(无自动排序)

http://blog.csdn.net/sdhongjun/article/details/4517325

1,hash_set 

http://blog.csdn.net/morewindows/article/details/7330323

2,hash_multiset 

3,hash_map 

http://blog.csdn.net/sdhongjun/article/details/4517325

4,hash_multimap

3,处理方法总结

3.1 密匙一、分而治之/Hash映射 + Hash/Trie统计 + 堆/快速/归并排序

【分而治之/hash映射】:针对数据太大,内存受限,只能是:把大文件化成(取模映射)小文件,即16字方针:大而化小,各个击破,缩小规模,逐个解决
【hash统计】:当大文件转化了小文件,那么我们便可以采用常规的hash_map(ip,value)来进行频率统计。
【堆/快速排序】:统计完了之后,便进行排序(可采取堆排序),得到次数最多的IP。

3.1.1 海量日志数据,提取出某日访问百度次数最多的那个IP

1.分析是否直接放入内存:不能
一个IP是32位的,即存储空间为4Bytes(相当于32位机器上的一个int型数据空间),而IP地址最多有2^32=4G种取值情况,所以单单做一个IP全地址的key的存储也需要2^32*4B = 16G Bytes,这种hashtable是不能完全加载到内存中处理; 
2.分而治之/Hash映射:
可以考虑采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件平均包含2^32/1024 = 4MB个IP地址; (如果其中的有的文件超过了4M*4B大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过4M*4B)
3.每个小文件做Hash统计:
对于每一个小文件,可以构建一个IP为key,出现次数为value(假如类型用int)的Hash map;占用空间大小为4MB * 4 Bytes = 16MB Bytes。
4.归并排序:
可以分别得到1024个小文件中出现次数最多的IP,再依据常规的排序算法得到总体上出现次数最多的IP;
【特别注意】
Hash取模是一种等价映射,不会存在同一个元素分散到不同小文件中去的情况,即这里采用的是mod1000算法,那么相同的IP在hash后,只可能落在同一个文件中,不可能被分散的。

3.1.2 寻找热门查询,300万个查询字符串中统计最热门的10个查询

原题:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

1.分析是否直接放入内存:可以
300万的Query,每个Query255Byte,因此我们可以考虑把他们都放进内存中去(300万个字符串假设没有重复,都是最大长度,那么最多占用内存3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理)
2.hash统计:
维护一个Key为Query字串,Value为该Query出现次数的HashTable,即hash_map(Query,Value)。O(N)的时间复杂度;
3.堆排序(top k):
借助堆这个数据结构,找出Top K,时间复杂度为NlogK。因此,维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比。所以,我们最终的时间复杂度是:O(N) + N' * O(logK),(N为1000万,N’为300万)。
【特别注意】
最大堆求前n小,最小堆求前n大。

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

1.分而治之/hash映射:
顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为a0,a1,..a9)中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。
1.2 hash统计:
找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。
1.3 堆/归并排序:
利用快速/堆/归并排序按照出现次数进行排序,将排序好的query和对应的query_cout输出到文件中,这样得到了10个排好序的文件(记为)。最后,对这10个文件进行归并排序(内排序与外排序相结合)。
【特别注意】
hash映射是必须的,需要重新将10个小文件扫一遍,然后hash到10个小文件中,因为hash映射保证相同的数据条目划分到同一个文件中进行运算。

3.1.4 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

1.分析是否直接放入内存:不能
估计每个文件安的大小为5G×64Bytes=320G Bytes,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理
2.分而治之/hash映射:
遍历文件a,对每个url求取hash(url)%1000,然后根据所取得的值将url分别存储到1000个小文件(记为a0,a1,...,a999)中。这样每个小文件的大约为320G Bytes/1000 = 300M。
遍历文件b,采取和a相同的方式将url分别存储到1000小文件(记为b0,b1,...,b999)。
这样处理后,所有可能相同的url都在对应的小文件(a0vsb0,a1vsb1,...,a999vsb999)中,不对应的小文件不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。
3.hash统计:
求每对小文件中相同的url时,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。
【特别注意】
这里不需要计算url频度,所以用hash_set就可以了。

3.2 密匙二、Bitmap

整数的个数是2^32 = 4 G,如果一个整数用1-BitMap表示是否存在,则需用4/ 8 G Bytes = 512 M Bytes.

3.2.1 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数

采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。
【特别注意】
int型整数做成1-Bitmap需要512M内存。
int型整数做成2-Bitmap需要1G内存。


3.3 密钥三、双层桶

3.3.1 5亿个int找它们的中位数

思路一:这个例子比上面那个更明显。首先我们将int划分为2^16个区域,然后读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中位数落到那个区域,同时知道这个区域中的第几大数刚好是中位数。然后第二次扫描我们只统计落在这个区域中的那些数就可以了。
实际上,如果不是int是int64,我们可以经过3次这样的划分即可降低到可以接受的程度。即可以先将int64分成2^24个区域,然后确定区域的第几大数,在将该区域分成2^20个子区域,然后确定是子区域的第几大数,然后子区域里的数的个数只有2^20,就可以直接利用direct addr table进行统计了。
  思路二@绿色夹克衫:同样需要做两遍统计,如果数据存在硬盘上,就需要读取2次。
方法同基数排序有些像,开一个大小为65536的Int数组,第一遍读取,统计Int32的高16位的情况,也就是0-65535,都算作0,65536 - 131071都算作1。就相当于用该数除以65536。Int32 除以 65536的结果不会超过65536种情况,因此开一个长度为65536的数组计数就可以。每读取一个数,数组中对应的计数+1,考虑有负数的情况,需要将结果加32768后,记录在相应的数组内。
第一遍统计之后,遍历数组,逐个累加统计,看中位数处于哪个区间,比如处于区间k,那么0- k-1的区间里数字的数量sum应该<n/2(2.5亿)。而k+1 - 65535的计数和也<n/2,第二遍统计同上面的方法类似,但这次只统计处于区间k的情况,也就是说(x / 65536) + 32768 = k。统计只统计低16位的情况。并且利用刚才统计的sum,比如sum = 2.49亿,那么现在就是要在低16位里面找100万个数(2.5亿-2.49亿)。这次计数之后,再统计一下,看中位数所处的区间,最后将高位和低位组合一下就是结果了。

3.4 密钥四、外排序

http://blog.csdn.net/v_JULY_v/article/details/6451990
适用范围:大数据的排序,去重

基本原理及要点:外排序的归并方法,置换选择败者树原理,最优归并树
扩展:
问题实例:
1).有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16个字节,内存限制大小是1M。返回频数最高的100个词。
这个数据具有很明显的特点,词的大小为16个字节,但是内存只有1m做hash有些不够,所以可以用来排序。内存可以当输入缓冲区使用。


 

原创粉丝点击