海量数据处理方法

1.hashing

   适用范围:快速查找,删除的基本数据结构,通常需要总数据量可以放入内存。
 这里的hashing和 hashmap是不一样的概念,这里的hash指的是hashtable可以看例子:(比较两个字符串的包含问题)
 
  海量数据处理方法_第1张图片
   问题实例:

  1).海量日志数据,提取出某日访问百度次数最多的那个IP。
   IP的数目还是有限的,最多2^32个,所以可以考虑使用hash将ip直接存入内存,然后进行统计。

2.bitmap
  适用范围:可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下。
    疑惑:bitmap处理的数据范围最大为多少?
    海量数据处理方法_第2张图片
    将bit-map扩展一下,用2bit表示一个数即可,0表示未出现,1表示出现一次,2表示出现2次及以上。或者我们不用2bit来进行表示,我们用两个bit-map即可模拟实现这个2bit-map。
    问题实例:

  1)已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
  8位最多99 999 999,大概需要99m个bit,大概10几m字节的内存即可。
  2)2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。

 
3.
     适用范围:海量数据前n大,并且n比较小,堆可以放入内存。
     问题实例:
  1)100w个数中找最大的前100个数。
  用一个100个元素大小的最小堆即可。
 
4.双层桶划分----其实本质上就是【分而治之】的思想,重在“分”的技巧上
   适用范围:第k大,中位数,不重复或重复的数字

 基本原理及要点:因为元素范围很大,不能利用直接寻址表,所以通过多次划分,逐步确定范围,然后最后在一个可以接受的范围内进行。可以通过多次缩小,双层只是一个例子。

  扩展:
  问题实例:
  1).2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。
  有点像鸽巢原理,整数个数为2^32,也就是,我们可以将这2^32个数,划分为2^8个区域(比如用单个文件代表一个区域),然后将数据分离到不同的区域,然后不同的区域在利用bitmap就可以直接解决了。也就是说只要有足够的磁盘空间,就可以很方便的解决。

  2).5亿个int找它们的中位数。
  这个例子比上面那个更明显。首先我们将int划分为2^16个区域,然后读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中位数落到那个区域,同时知道这个区域中的第几大数刚好是中位数。然后第二次扫描我们只统计落在这个区域中的那些数就可以了。

这个看的不是很明白。

  
5.倒排索引
   适用范围:搜索引擎,关键字查询

  基本原理及要点:为何叫倒排索引?一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。

 以英文为例,下面是要被索引的文本:
    T0 = "it is what it is"
    T1 = "what is it"
    T2 = "it is a banana"

我们就能得到下面的反向文件索引:

    "a":      {2}
    "banana": {2}
    "is":     {0, 1, 2}
    "it":     {0, 1, 2}
    "what":   {0, 1}

 检索的条件"what","is"和"it"将对应集合的交集。

扩展:
  问题实例:文档检索系统,查询那些文件包含了某单词,比如常见的学术论文的关键字搜索。
 

6.外排序 --归并排序
    适用范围:大数据的排序,去重
    一般处理海量数据的时候,首先用hashmap分到较小的文件中,或者是mapreduce分配到多个计算机中,然后再通过归约来进行统计。
    问题实例:

  1).有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16个字节,内存限制大小是1M。返回频数最高的100个词。

  这个数据具有很明显的特点,词的大小为16个字节,但是内存只有1m做hash有些不够,所以可以用外排序。内存可以当输入缓冲区使用。首先就是hashmap到不同文件中。

 7.mapreduce
    海量数据处理方法_第3张图片
 
8.trie树(字典树)

  树形见:
海量数据处理方法_第4张图片
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
  Trie树的基本性质可以归纳为 : 
 (1)根节点不包含字符,除根节点意外每个节点只包含一个字符。
 (2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。 
 (3)每个节点的所有子节点包含的字符串不相同
  时间空间复杂度分析:
  1)使用hash:我们用hash存下所有字符串的所有的前缀子串。建立存有子串hash的复杂度为O(n*len)。查询的复杂度为O(n)* O(1)= O(n)。
  2)使用Trie:因为当查询如字符串abc是否为某个字符串的前缀时,显然以b、c、d....等不是以a开头的字符串就不用查找了,
  这样迅速缩小查找的范围和提高查找的针对性。对于每个字符,需要遍历n个(本例中26)字符来判断是否存在,所以建立Trie的复杂度为O(n*len),
  而建立+查询在trie中是可以同时执行的,建立的过程也就可以成为查询的过程,hash就不能实现这个功能。所以总的复杂度为O(n*len),
  实际查询的复杂度只是O(len)。
 
  字典树(Trie)可以保存一些字符串->值的对应关系。基本上,它跟 Java 的 HashMap 功能相同,都是 key-value 映射,只不过 Trie 的 key 只能是字符串。
 
  效率分析:
   当存储大量字符串时,Trie耗费的空间较少。因为键值并非显式存储的,而是与其他键值共享子串。相当于此时相同的字符很多,公共的话会减少储存空间,尽管此时每个节点需要26个空间节点的大小,单相对字符串数目算不了什么。
海量数据处理方法_第5张图片
 
代码:
海量数据处理方法_第6张图片
海量数据处理方法_第7张图片
代码解析:

1.插入

  假设存在字符串str,Trie树的根结点为root。i=0,p=root。

  1)取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;

   若不为空,则p=p->next[str[i]-97];

  2)i++,继续取str[i],循环1)中的操作,直到遇到结束符'\0',此时将当前结点p中count++。

2.查找

  假设要查找的字符串为str,Trie树的根结点为root,i=0,p=root

  1)取str[i],判断判断p->next[str[i]-97]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-97],继续取字符。

  2)重复1)中的操作直到遇到结束符'\0',若当前结点p不为空,则返回true,否则返回false。

3.删除

  删除可以以递归的形式进行删除。

 

有个实例的解法很好,这里贴上去
海量数据处理方法_第8张图片
 
本文只是相当于笔记,便于日后复习。内容全部来自 http://blog.csdn.net/v_JULY_v/article/details/6279498 
  
 
 
 





你可能感兴趣的:(海量数据)