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

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

哈希切分


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

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

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

  • 另外,如果我们使用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亿个整数,设计算法找到只出现一次的整数

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

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

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

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

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

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

  • 该问题如果直接使用位图的话,一个数有四种状态:不存在,出现一次,出现两次,出现多次。所以需要使用两个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的速度越快,且布隆过滤器的效率越低;但是如果太少的话,误报率会变高
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值