秒杀99%海量数据处理问题 (总结与July 博客)

何谓海量数据处理?

①所谓海量数据处理,无非就是基于海量数据上的存储、处理、操作
②问题?
   数据量太大:导致无法在较短时间内迅速解决, 无法一次性装入内存进行处理。
③解决办法?
    针对时间:我们可以采用巧妙的算法搭配合适的数据结构,如Bloom filter/Hash/bit-map/堆/数据库或倒排索引/trie树
    针对空间:无非就一个办法:大而化小,分而治之(hash映射) 
④   单机及集群问题
       单机:就是处理装载数据的机器有限(只要考虑cpu,内存,硬盘的数据交互) 
       集群:机器有多台,适合分布式处理,并行计算(更多考虑节点和节点间的数据交互)。

海量数据处理办法?

   根据july博客 :Big Data Processing,我们已经大致知道,处理海量数据问题,无非就是:

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

STL的容器可以分为以下几个大类:

一:序列容器, 有vector, list, deque, string.

二 : 关联容器,     有set, multiset, map, mulmap, hash_set, hash_map, hash_multiset, hash_multimap

三: 其他的杂项: stack, queue, valarray, bitset

具体知识参考(转自于博客园)

具体算法研究和实现参考(STL他山之石)  

  • 关于什么hash,请看blog内此篇文章
  • 关于红黑树,请参看blog内系列文章
  • 关于hash_map的具体应用:请看这里,关于hash_set:请看此文

什么样的结构决定其什么样的性质,因为set/map/multiset/multimap都是基于RB-tree之上,所以有自动排序功能,而hash_set/hash_map/hash_multiset/hash_multimap都是基于hashtable之上,所以不含有自动排序功能,至于加个前缀multi_无非就是允许键值重复而已


处理海量数据问题之六把密匙


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

1、海量日志数据,提取出某日访问百度次数最多的那个IP。 
 解析:
①:把百度的日志中的IP取出来,逐个写入到一个大文件中, IP是32位的,最多有个2^32个IP 
②:采用映射的方法,比如%1000,把整个大文件映射为1000个小文件 (其中每个小文件中可以有多个不同的ip,但是相同的ip经过映射(取余)后会在同一个小文件中的)
③:运用hash_map映射每个小文件中每个IP到一个桶内,计算每个桶内的个数(即每个ip的数量)。
注意:如果出现hash冲突了(即一个桶内有多个IP,那么可以采用二次探测再散列法直到每个桶内只有一个ip为止
④:根据③每个文件最大ip已经计算出来了,一共1000个,然后再通过堆/快速排序 ,得到次数最多的IP。
有兴趣的,还可以再了解下一致性hash算法,见blog内此文第五部分:http://blog.csdn.net/v_july_v/article/details/6879101

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

    解析:由上面第1题,我们知道,数据大则划为小的,但如果数据规模比较小,能一次性装入内存呢?比如这第2题,虽然有一千万个Query,但是由于重复度比较高,因此事实上只有300万的Query,每个Query255Byte,因此我们可以考虑把他们都放进内存中去(300万个字符串假设没有重复,都是最大长度,那么最多占用内存3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理),而现在只是需要一个合适的数据结构,在这里,HashTable绝对是我们优先的选择。所以我们放弃分而治之/hash映射的步骤,直接上hash统计,然后排序。So,针对此类典型的TOP K问题,采取的对策往往是:hashmap + 堆。如下所示:

  1. hash_map统计:先对这批海量数据预处理。具体方法是:维护一个Key为Query字串,Value为该Query出现次数的HashTable,即hash_map(Query,Value),每次读取一个Query,如果该字串不在Table中,那么加入该字串,并且将Value值设为1;如果该字串在Table中,那么将该字串的计数加一即可。最终我们在O(N)的时间复杂度内用Hash表完成了统计;
  2. 堆排序:第二步、借助堆这个数据结构,找出Top K,时间复杂度为N‘logK。即借助堆结构,我们可以在log量级的时间内查找和调整/移动。因此,维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比。所以,我们最终的时间复杂度是:O(N) + N' * O(logK),(N为1000万,N’为300万)。


堆排序(时间复杂度计算)
建堆是自底向上的且序列位于无序状态,此时除了要选取堆顶元素以外还要保证所有子树的根与左右结点之间符合堆的标准(根是三个结点中取值最小的(小顶堆,降序)/最大的(大顶堆,升序))。
堆调整是自顶向下的序列处于基本有序状态。此时只需要关注自顶向下移动路径上的各个分支是否在交换后依然符合堆的标准。
建堆复杂度计算( 为 o(n))

j
建好堆以后,每次调整的复杂度为(o(logn))
因为每一次调整堆的时候,堆是有序的,只是把最上面的数用新的数替代后,需要对它进行调整,如果堆存放的数据为n的话,那么二叉树的高度为log(n),即最上面的数,最多向下调整log(n)-1次,,所以复杂度为o(logn)


3、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
(该题结合了上面2道题的思想) 本题不仅文件很大,又是内存受限:策略是  (分而治之 + hash统计 + 堆/快速排序/归并)
  解析:
  1. 分而治之/hash映射:顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为x0,x1,...x4999)中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M。
  2. hash_map统计:对每个小文件,采用trie树/hash_map等统计每个文件中出现的词以及相应的频率。
  3. 堆/归并排序:取出出现频率最大的100个词(可以用含100个结点的最小堆)后,再把100个词及相应的频率存入文件,这样又得到了5000个文件。最后就是把这5000个文件进行归并(类似于归并排序)的过程了。
我的误区:统计前100词的,不能只统计每个文件最大值,然后在所有文件中找出前100
因为:有可能top100都在一个文件当中,如果像我这样统计的话,出来的100个数不一定是最大值了哦,注意啊!!!!!!!






           












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值