一、布隆过滤器

  问题:不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL最多占用64B。现在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单上,如何设计该系统。

  要求:允许有万分之一以下的判断失误率;使用的额外空间不能超过30GB

  思路:如果把黑名单中所有的URL通过数据库或者哈希表保存下来,至少需要640GB的空间。

  解答:如果遇到网页黑名单系统、垃圾邮件过滤系统、爬虫的网址判重系统等题目,并且系统容忍一定程度的失误率以及对空间要求比较严格,那么需要用布隆过滤器来解答。布隆过滤器精确地代表一个集合,并可以精确判断一个元素是否在集合中。但是想做到完全正确是不可能的。布隆过滤器的优势就在于使用很少的空间就可以将准确率做到很高的程度。

  基础知识:哈希函数的性质:(1)典型的哈希函数都有无限的输入值域(2)当给哈希函数传入相同的输入值时,返回值一样(3)当个哈希函数传入不同的输入值时,返回值可能一样,也可能不一样(4)最重要的性质是返回值会均匀地分布在固定范围的输出域上。第四点性质是评价一个哈希函数优劣的关键,不同输入值所得到的所有返回值越均匀地分布在输出域S上, 哈希函数越优秀,并且这种均匀分布与输入值出现的规律无关。哈希函数经典的实现包括MD5和SHA1算法。如果一个优秀的哈希函数能够做到很多不同的输入值所得到的返回值非常均匀地分布在S上,那么所有返回值对m取余也会均匀地分布在0~m-1的空间上。

  布隆过滤器的生成:(1)有一个长度为m的bit类型的数组。(2)有k个哈希函数,这些函数的输出域S都大于或等于m,并且这些哈希函数都足够优秀,彼此之间也完全独立。那么对同一个输入对象(假设是一个字符串记为URL),经过k个哈希函数算出来的结果也是独立的,可能相同,也可能不同,但彼此独立。对算出来的每一个结果都对m取余,然后在bit数组中把对应的位置设置成1。(3)把bit类型的数组记为bitMap,对于一个输入对象来说,对bitMap的影响就是把bitMap的一些位置设置成1(涂黑)。然后按照该规则处理所有的输入对象,每个对象都可能把bitMap中的一些白位置涂黑,也可能将黑位置继续涂黑。完成后,一个布隆过滤器就生成完毕,代表之前所有输入对象组成的集合。

  布隆过滤器的判断:假设一个对象为a,要想检查它是否之前已经输入到bitMap中,只需要把a通过k个哈希函数算出k个值并取余,就得到[0...m-1]范围上的k个值,然后查看bitMap中这些位置是否为黑,如果有一个不为黑,就说明a一定不在集合里。如果都为黑,说明在这个集合里,也可能会误判。误判的原因是:由于布隆过滤器在生成时输入对象过多同时bitMap过小,会导致bitMap大部分的位置都是黑的,这时不在集合里的a对应的k个位置可能都是黑的,从而错误地认为a在集合里。

  布隆过滤器的失误率:假设布隆过滤器的大小是m,哈希函数的个数是k,需要输入的对象个数为n,失误率是p,则经过推导可以得到

  

  带入到题目中,n=100亿,p=0.01%,(每个样本大小64B,这个信息不会影响布隆过滤器的大小,只和选择哈希函数有关,一般的哈希函数都可以接受64B的输入对象,所以使用布隆过滤器还有一个好处是不用顾忌单个样本的大小,丝毫不能影响布隆过滤器的大小)

  m=19.19n,向上取整为20n,即需要2000亿个bit,即25GB。再由k=0.7×(m/n)=14就确定了需要哈希函数的个数为14个。

  布隆过滤器误判解决:可以把确实不在集合中,但每次计算结果都在集合中的误报样本加入到白名单,以后就可以知道这个样本确实不在集合中了。

  二、只用2GB内存在20亿个整数中找到出现次数最多的数

  问题:有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数。内存限制为2GB。

  思路:想要在很多整数中找到出现次数最多的数,通常的做法是使用哈希表对出现的每一个数做词频统计,哈希表的key是某一个整数,value是这个数出现的次数。如果一个数出现了20亿次,用32位的整数也可以表示其出现的次数,而不会产生溢出,所以哈希表的key需要占用4B,value也是4B,一条哈希表的记录(key,value)需要占用8B,当哈希表记录数为2亿个时,至少需要1.6GB的内存。如果20亿个树中不同的数超过2亿种,,最极端的情况是20亿个数都不同,那么内存会不够用,所以一次性用哈希表统计20亿个数的办法是有风险的。

  解决办法:把包含20亿个数的大文件用哈希函数分成16个小文件,根据哈希函数的性质,同一种数不可能被哈希到不同的文件上,同时每个小文件中不同的数一定不会大于2亿种(20/2=10,而16>10)。然后对每一个小文件用哈希表来统计其中每种数出现的次数,这样就得到了16个小文件中各自出现次数最多的数,以及各自的次数统计。然后比较这16个文件中出现次数最多的数中出现次数最大的就行了。

  把一个大的集合通过哈希函数分配到多台机器中,或者分配到多个文件里,这种技巧是处理大数据面试题时最常用的技巧之一。

  三、40亿个非负整数中找到没出现的数

  32位无符号整数的范围是0~4294967295,现在正好有一个包含40亿个无符号整数的文件,所以在文件中必然没有出现过的数。

  题目1:最多使用1GB,找到所有每出现过的数。

  如果40亿个数都不同,则哈希表记录数为40亿条,所需要空间40亿×4B=16GB,显然不符合要求。

  正确思路:由于哈希表需要占用很多空间,因此可以使用bit map的方式来表示数出现的情况。即申请一个长度为4294967295的bit类型的数组bitArr,bitArr上每一个位置只可以表示0或1。由于1B=8bit,所以4294967295个bit占用空间为500MB。

  使用方法:遍历这40亿个无符号数,把bitArr对应位置上置1。例如,如果遍历到7000,就把bitArr[7000]置为1。遍历完成后,再遍历一遍,发现哪个位置上的值不是1,就说明这个数不在40亿个数中。

  问题2:最多使用1GB,找出所有出现了两次的数。

  使用bit map的方式来表示数出现的情况,即申请一个长度为4294967295×2的bit类型的数组bitArr,由于1B=8bit,所以所以4294967295 × 2个bit占用空间为1GB。遍历这40亿个数,如果第一次遇到num,就把bitArr[num*2+1]和bitArr[num*2]设置为01,第二次设置为10,第三次设置为11,只有就不再管了。然后依次遍历bitArr,如果发现bitArr[num*2+1]和bitArr[num*2]为10,那么i就是出现了两次的数。

  题目3:最多使用10MB,只用找到一个没出现过的数即可。

  思路:将0~4294967295区间平均分成64个区间,每个区间是67108864个数,由于只有40亿个数,因此至少有一个区间上的计数少于67108864。

  第一次遍历:申请长度为64的整形数组countArr[0...63],countArr[i]表示区间i上的数有多少个。例如,遍历到3422552090时,3422552090/67108864=51,因此countArr[51]++。遍历完40亿个数之后,一定存在count[i]小于67108864,找到第一个i即可。此时内存为64×4B。

  第二次遍历:假设第一步的i=37。申请长度为67108864的bit map,内存大小大约为8MB,记为bitArr[0...67108863]。然后再遍历一次40亿个数,此时只关注落在第37区间的数,即满足num/67108864=37的num。然后将bitArr[num - 67108864*37]=1,然后遍历bitArr,找到bitArr[i]不等于1的i值,然后67108864×37+i就是第一个没出现过的数。

  问题4:最多使用10MB,找到这40亿个整数的中位数。

  长度为2MB的无符号整型数组占用的空间为8MB,所以将区间的数量定位4294967295/2M=2148个。申请一个长度为2148的无符号整型数组arr[0...2147],arr[i]表示第i区间有多少个数。然后遍历这40亿个数,将对应的进行arr[num/2M]++操作,然后累加每个区间的出现次数,如果0~K-1区间上的数的个数为19.998亿,但是当加上第K个区间上的数的个数后就超过了20亿,因此第20亿个数是第K区间上第0.002亿个数。

  然后申请一个长度为2MB的无符号整型数组countArr[0...2M-1],占用空间是8MB。然后遍历这40亿个数,只对第K区间的数做统计,jicountArr[numi - K * 2M]++,然后只在第K区间上找到第0.002亿个数即可。

  四、找到100亿个URL中重复的URL以及搜索词汇的Top K问题

  问题1:有一个包含100亿个URL的大文件,每个URL占用64B,找出其中所有重复的URL。

  首先需要明确在资源上的限制有哪些,包括内存、计算时间等要求。总的思路就是将每条URL通过哈希函数分配到若干几区或者拆分成若干个小文件,这里的“若干”由具体的资源限制来计算出精确的数量。然后每一台机器或者每一个小文件分别统计是否有重复的URL出现。

  问题2:某搜索公司一天的用户搜索词汇是海量的(百亿数量级),设计一种求出每天最热top 100词汇的方法。

  先把包含百亿数据量的词汇文件分流到不同的机器上,然后对每一台机器来说,如果分到的数据量依然很大,可以再用哈希函数把每台机器上的分流文件拆分成更小的文件。处理每一个小文件的时候,使用哈希表统计词频信息。然后遍历哈希表,使用大小为100的小根堆来选出每一个小文件的top100,然后将小根堆(最小堆)里的词按照词频进行排序,就得到了每个小文件排序后的top 100。然后把各个小文件排序后的top 100进行外排序或者继续利用小根堆(最小堆),就可以选出每台机器上的top 100。不同机器之间的top 100在进行外排序或者继续利用小根堆(最小堆),最终求出整个百亿数据量中的top 100。(使用堆结构和外部排序

  

  五、一致性哈希算法的基本原理

  题目:常见的数据缓存策略是这样的:1.无论是添加、查询还是删除数据,都先将数据的id通过哈希函数转换成一个哈希值,记为key。2.如果当前机器有N台,则计算key%N的值,这个值就是该数据所属的机器编号,无论是添加、删除还是查询操作,都只能在这台机器上进行。分析这种缓存策略可能带来的问题,并提出改进方案。

  存在的问题:如果增加或者删除机器时(N变化),代价会很高,所有的数组都不得不根据id重新计算一遍哈希值,并将哈希值对新的机器进行取模计算,然后进行大规模的数据迁移。

  改进方法:一致性哈希算法是一种很好的数据缓存设计方案。

  第一步:假设数据的id通过哈希函数转换成的哈希值范围是在0~232-1的数字空间中,先将这些数字头尾相连,那么一个数据id在计算出哈希值之后认为对应到环中的一个位置。

  第二步:将机器添加到上面的环中,机器在环中的位置是根据机器id计算出来的哈希值决定。对于一条数据来说,首先把该数据的id用哈希函数计算出哈希值,并映射到环中相应位置,然后顺时针寻找离这个位置最近的机器。

  第三步:添加机器时,首先根据机器id得到机器处于原来哪两台机器的中间,然后把某一段数据迁移到新机器上就行了。删除机器时,只要把要删除机器的数据全部复制到顺时针找到的下一台机器上即可。

  第四步:机器负载不均时的处理。如果机器较少,很有可能造成机器在整个还上的分布不均匀,从而导致机器之间的负载不均衡。为了解决数据倾斜的问题,一致性哈希算法引入了虚拟节点机制,即对每一台机器通过不同的哈希函数计算出多个哈希值,对多个位置都放置一个服务节点,称为虚拟节点。具体做法可以在机器ip或主机名的后面增加编号或端口号来实现。例如,一个实际机器节点对应着两个虚拟节点,节点变多了,根据哈希函数的性质,平衡性自然会变好。同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射。

  

  

OptimalSolution(7)--大数据和空间限制的更多相关文章

  1. GIS-"地理空间大数据与AI的碰撞"学习笔记

    1.关系 人工智能>机器学习>神经网络>深度学习 2.机器学习-两个过程 训练/学习过程:样本数据.学习器.模型参数 测试/预测过程:预测.预测值 3.神经网络 机器学习模拟人脑神经 ...

  2. 构建AR视频空间大数据平台(物联网及工业互联网、视频、AI场景识别)

    目       录 1.      应用背景... 2 2.      系统框架... 2 3.      AI场景识别算法和硬件... 3 4.      AR视频空间管理系统... 5 5.    ...

  3. 大数据量场景下storm自定义分组与Hbase预分区完美结合大幅度节省内存空间

    前言:在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗.大量的预分 ...

  4. 利用BitMap进行大数据排序去重

    1.问题 问题提出: M(如10亿)个int整数,只有其中N个数重复出现过,读取到内存中并将重复的整数删除. 2.解决方案 问题分析: 我们肯定会先想到在计算机内存中开辟M个int整型数据数组,来on ...

  5. 分布式大数据高并发的web开发框架

    一.引言 通常我们认为静态网页html的网站速度是最快的,但是自从有了动态网页之后,很多交互数据都从数据库查询而来,数据也是经常变化的,除了一些新闻资讯类的网站,使用html静态化来提高访问速度是不太 ...

  6. POI3.8解决导出大数据量excel文件时内存溢出的问题

    POI3.8的SXSSF包是XSSF的一个扩展版本,支持流处理,在生成大数据量的电子表格且堆空间有限时使用.SXSSF通过限制内存中可访问的记录行数来实现其低内存利用,当达到限定值时,新一行数据的加入 ...

  7. Hadoop 和 HDInsight:Windows Azure 中的大数据

    世界的大数据包含一个庞大而充满活力的生态系统,但一个开放源码项目上面有这一切,那就是 Hadoop 的王朝. Hadoop 是事实上的标准的分布式的数据运算.Hadoop 提供了一个 MapReduc ...

  8. 大数据系列(2)——Hadoop集群坏境CentOS安装

    前言 前面我们主要分析了搭建Hadoop集群所需要准备的内容和一些提前规划好的项,本篇我们主要来分析如何安装CentOS操作系统,以及一些基础的设置,闲言少叙,我们进入本篇的正题. 技术准备 VMwa ...

  9. 第六章 大数据,6.3 突破传统,4k大屏的沉浸式体验(作者: 彦川、小丛)

    6.3 突破传统,4k大屏的沉浸式体验 前言 能够在 4K 的页面上表演,对设计师和前端开发来说,即是机会也是挑战,我们可以有更大的空间设计宏观的场景,炫酷的转场,让观众感受影院式视觉体验,但是,又必 ...

随机推荐

  1. C#之WPF连接sqllite数据库

    using System; using System.Collections.Generic; using System.Data; using System.Data.SQLite; namespa ...

  2. GetThreadTimes获取其它线程cpu时间

    http://www.cnblogs.com/eaglet/archive/2009/03/11/1408809.html 鄙视下上面的垃圾博文,纯粹忽悠人 参考文章: http://blog.kal ...

  3. java多线程技术核心

    1.进程的三大特征: 独立性:拥有自己的独立的地址空间,一个进程不可以直接去访问其他进程的地址空间. 动态性:是一个系统中活动的指令的集合. 并发性:单个进程可以在多个处理器上并发进行,互不影响. 2 ...

  4. .NET开发者必须学习.NET Core

    很多的.NET开发者在接触.Net Core之前,对于linux系统一点也不了解,也未曾有过主动去学习的念头.在接触了.Net Core之后才会慢慢学习linux相关知识,很多同学想转Java,这个很 ...

  5. 使用 chart 部署 skywalking

    使用 chart 部署 skywalking 本文主要讲述的是如何使用 Helm Charts 将 SkyWalking 部署到 Kubernetes 集群中,相关文档可以参考skywalking-k ...

  6. FFmpeg(二) 解封装相关函数理解

    一.解封装基本流程 ①av_register_All()////初始化解封装,注册解析和封装的格式. ②avformat_netword_init()//初始化网络,解析rtsp协议 ③avforma ...

  7. 网络游戏开发-客户端1(开始Hello world)

    打开Egret Launcher ,新建一个EUI项目,起名为 EQiPai 这里需要勾选的是socket网络库,game游戏库.如果要面向海外用户的话,建议勾上Facebook的小游戏sdk. 然后 ...

  8. ES6——箭头函数与普通函数的区别

    ES6标准新增了一种新的函数:Arrow Function(箭头函数). 为什么叫Arrow Function?因为它的定义用的就是一个箭头: 语法: //1.没有形参的时候 let fun = () ...

  9. python编程基础之二十二

    字典:字典属于可变对象,但是不属于序列,内部是通过哈希方式存储的,内部保存的是一个个键值对key:value 字典的键是唯一的, 字典查找速度比较快 d1 = {}  #括号里面用键值对表示 d2 = ...

  10. 最简单的ArcGIS Engine应用程序(中)

    上一篇中只能添加代码中指定的shp文件(最简单的ArcGIS Engine应用程序(上)) 为了让用户可以浏览磁盘加载指定的shp文件,需做一下调整. 从工具箱往窗体上添加一个OpenFileDial ...