『数据结构』海量数据处理

本篇博客咱们经过几个经典的问题来看一下计算机中处理海量数据的经常使用方法。web

哈希切分


问题:给定一个超过100G大小的日志文件,文件中保存着IP地址,设计算法找出出现次数最多的IP地址?如何找到出现次数topK的IP?如何直接用Linux命令实现算法

  • 找到出现次数最多或者前K多的IP地址并不困难,直接使用优先级队列就能够解决该问题。这道题真正困难的是100G大小的日志文件,由于咱们经常使用的计算机并无这么大的内存。可能你会说咱们找一个有这么大内存的机器来处理不就行了,这样也不是不能够。可是若是咱们的日志文件大小为1000G或者10000G呢,或者更大,由于磁盘的空间确定是远大于内存空间大小的。因此咱们须要别的办法来处理这个问题。
  • 咱们使用切分的思想,将一个大文件切分红不少个小文件,这样这些小文件就能够分别加载到内存中进行统计。可是这里有一个问题,就是咱们必须保证相同的IP地址可以被分到同一个小文件中,这样正确的统计出每一个IP的出现次数,因此咱们使用哈希切分,哈希切分,经过哈希函数来计算该IP地址应该被切分到哪一个小文件中,这样就能保证相同的IP地址被切分到同一个文件中。
  • 经过前面的哈希切分,咱们就能够获得不少个小文件,咱们将每个小文件加载到内存中,找出这个小文件中出现次数最多的IP地址,重复这个过程,咱们就能够获得每个小文件中出现次数最多的IP地址
  • 上一步咱们能够获得每一个小文件中出现次数最多的IP地址,咱们就能够将这些IP地址经过一个优先级队列来找到出现次数最多或者前K多的IP地址

上述过程的示意图以下
在这里插入图片描述shell

  • 另外,若是咱们使用Linux来操做的话,能够使用grep命令来实现上述功能
grep -i -o -E "([0-9]{1,3}\.){3}[0-9]{1,3}" logfile.txt | sort -n | uniq -c | sort -n -r | head -K

位图应用


问题一:给40亿个不重复的无符号整数没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中数组

  • 这种问题就是判断一个数是否在一个集合中,咱们一般的作法就是将这些数据存到一个Set中,而后就能够快速判断一个数是否在这个集合中。可是当前的场景明显不行,由于数据量太大了,大到内存中存不下。咱们有40亿个无符号整数一个无符号整数是4个字节,因此40亿个无符号整数就是160亿个字节大约就是16G的内存才能存的下,很明显,使用Set明显是不行的。
  • 所以咱们可使用位图的方式来表示。数据是否在给定的整型数据中,结果是在或者不在,恰好是两种状态,那么能够使用一个二进制比特位来表明数据是否存在的信息,若是二进制比特位为1,表明存在,为0表明不存在
  • 所以保存40亿个不重复的无符号整数的状态只须要40亿个bit位的空间,即5亿个字节大约500M的内存空间便可保存。所以咱们将这40亿个不重复的整数的状态保存到数组中
  • 咱们判断一个数是否在这40亿个整数中,只须要查看数组中该下标位置中的内容是0仍是1,若是为0表示不存在,若是为1表示存在

位图的大体结构以下
在这里插入图片描述数据结构

问题二:给定100亿个整数,设计算法找到只出现一次的整数svg

  • 该问题和上个问题差很少,也是用位图的思路来解决,上个问题每一个数只有两个状态,即存在和不存在,因此使用一个bit位来表示。而本问题每一个数存在三个状态,即:不存在出现一次出现屡次。因此咱们须要使用两个bit位来表示一个数的状态,即:00表示不存在01表示出现一次10表示出现屡次。按照这种方法,每一个整数须要2个bit位,因此一共须要200亿个bit位,即25亿个字节大约2.5G的内存,这个内存对咱们来讲仍是占用太大。
  • 由于直接使用位图的方式须要2.5G的内存,仍是占用太大,因此咱们能够借助哈希切分的思想来解决这个问题。咱们经过一个哈希函数将一个大文件切分红多个小文件,而后分别对每一个小文件使用位图的思想来解决该问题。找到每一个小文件中出现次数为1的数字,汇总起来就是最终的结果。

上述过程的示意图以下
在这里插入图片描述函数

问题三:给两个文件分别有100亿个整数,咱们只有1G内存,如何找到两个文件交集spa

  • 若是咱们直接使用位图的方式,每一个数据有两个状态,即存在和不存在,所以可使用一个bit位来表示,0表示不存在,1表示存在。所以咱们须要100亿个bit位,大约1.25G的内存,显然不符合题意。
  • 所以咱们使用哈希切分的思想对两个文件使用相同的哈希函数进行切分。而后分别对对应的小文件使用位图的方式求交集,最后将全部的结果进行汇总就是最终的结果
  • 对两个小文件使用位图求交集,首先根据一个文件来构建位图,而后从另外一个文件中读数据,若是这个数据在位图中存在,说明是这个数在交集中,重复这个过程便可的到两个小文件的交集。

上述过程的示意图以下
在这里插入图片描述设计

问题四:一个文件有100亿个int1G内存,设计算法找到出现次数不超过2次的全部整数3d

  • 该问题若是直接使用位图的话,一个数有四种状态:不存在,出现一次,出现两次,出现屡次。因此须要使用两个bit位来表示,即须要200亿个bit,大约2.5G内存,显然是不行的。
  • 因此这个问题咱们仍是须要借助哈希切分的思想来解决,咱们使用哈希函数将一个文件切成多个小文件,而后对每一个小文件使用位图的方式来找到出现次数不超过两次的整数
  • 对于每一个小文件,每一个数据使用两个bit位来表示。即:00表示不存在,01表示出现1次,10表示出现两次,11表示出现次数超过两次。

上述过程的示意图大体以下
在这里插入图片描述

布隆过滤器


什么是布隆过滤器?


本质上布隆过滤器是一种数据结构,比较巧妙的几率型数据结构,特色是高效的插入和查询,能够用来告诉你“某样东西必定不存在或者可能存在”
布隆过滤器使用位图的方式实现,相比于传统的List、Set、Map等数据结构,它更高效、占用空间更少,可是缺点是其返回的结果是几率性的,而不是确切的

布隆过滤器数据结构


  • 布隆过滤器大概长这样
    在这里插入图片描述
  • 若是咱们要映射一个值到布隆过滤器中,咱们须要使用多个不一样的哈希函数生成多个哈希值,并对每一个生成的哈希值指向的bit位置为1,例如针对值“Alibaba”和三个不一样的哈希函数分别生成了三个哈希值1,4,7,则上图转变为:
    在这里插入图片描述
  • 此时咱们再插入一个值“Tencent”,如何哈希函数返回3,4,8的话,图转变成以下:
    在这里插入图片描述
  • 值得注意的是,下标为4的bit位因为两个值的哈希函数都返回了这个bit位,所以它被覆盖了。如今若是咱们想要查询“ByteDance”这个值是否存在,哈希函数反悔了1,5,8三个值,结果咱们发现5这个bit位上为0,说明没有任何一个值映射到这个bit位上,所以咱们能够很肯定的说“ByteDance”这个值不存在
    可是当咱们查询“Alibaba”这个值是否存在的话,那么哈希函数必然会返回1,4,7,而后咱们检查发现这三个bit位上的值均为1,那么咱们能够说“Alibaba”存在了吗?答案是不能够,只能说“Alibaba”这个值可能存在。答案很简单,由于随着增长的值愈来愈多,被置为1的bit位也会愈来愈多,这样某个值“ByteDance”即便没有被存储过,可是万一哈希函数返回的三个bit位都被其余值置为了1,那么程序仍是会判断“ByteDance”这个值存在

布隆过滤器支持删除吗?


传统的布隆过滤器不支持删除,由于可能有多个值对某一个bit位置1,所以不支持删除操做,若是想要支持删除操做,就不能使用位图的结构,将一个bit位调整成一个整数,用于统计被置1的次数,相似于一个计数器,删除时,对对应的位进行减减操做。可是这样空间就会消耗很大。

如何选择哈希函数个数和布隆过滤器长度


  • 很显然,太小的布隆过滤器很快全部的bit位均为1,那么查询任何值都会“可能存在”,起不到过滤的目的了。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小
  • 另外,哈希函数的个数也须要权衡,个数越多则布隆过滤器bit位置1的速度越快,且布隆过滤器的效率越低;可是若是太少的话,误报率会变高