热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

海量数据处理hash和bitmap

问题实例:海量日志数据,提取出某日访问百度次数最多的那个IP。答:对于ip,最多也就2^32个。所以可以很好地通过hash函数映射到内存中,再进行统计。原理简述:hash的基本原理

问题实例: 
海量日志数据,提取出某日访问百度次数最多的那个IP。 

答:对于ip,最多也就2^32个。所以可以很好地通过hash函数映射到内存中,再进行统计。

IP最多为2^32个,为4G,一次放入内存中不行,可以采用分而治之的方法,先Hash(IP)/1024,将IP地址分别映射到1024个小文件中,每个文件4M,再将每个小文件中的IP放入内存中,进行hashmap,统计出出现频率最高的那个IP,最后可以得到1024个出现高频的IP,采用冒泡排序,可以迅速找出频率最高的那个IP.1

原理简述:

hash的基本原理网上也已经很多了,下面简单提一下。

在ssh协议加密中,sha-1就是通过哈希来进行的。哈希就是将一个字符串或者其他数字之类的,转换成其他好处理的数据。

主要问题是会存在碰撞,所以常用的解决哈希碰撞的方法是:一个是开地址,一个是开链。前者是通过碰撞寻找新地址来实现,后者是每个地址维护一个

链表存储相同的元素。

bitmap其实就是之前bloom filter的基础。主要原理还是通过映射达到空间压缩的目的。

下面转载一道别人结合两种方法处理的一个问题。并且通过bloom filter进行了优化

http://blog.csdn.net/dyllove98/article/details/9199359

标题用了了海量数据(Massive datasets)而不用大数据(Big data)。感觉大数据还是略微有点虚,来点实际的。

一、需求

现在我们需要设计一个在线过滤垃圾邮件地址的方案,我们的数据库里面已经有10亿个合法的邮件地址(称为合法地址集S),当有新的邮件发过来时,要检查这个邮件地址是不是在我们的数据库里面,如果在,我们接收邮件,如果不在,我们就把它当做垃圾邮件过滤掉。

二、直觉想到的方法

一拿到这个问题,我就想到了用log(n)的折半查找,先将10亿个邮件地址排序,当收到一个邮件地址时,我利用折半查找,看邮件地址是否在S中,log(1,000,000,000) = 29.89约等于30,对每一个邮件地址我最多也只需要查找30次,感觉也挺快的,应该能满足要求。仔细想一下,折半查找必须放入内存,10个邮件地址还差不多,10亿个邮件地址我们来算一算有多大,邮件地址平均长度按20个字符计算,一个字符占用1Byte,一个email就占了20B,1,000,000,000X20B = 20GB,内存顶得住么,当然可以分多段进行折半,当分段需要多次I/O操作,需要的时间已经不是在线过滤所能承受的了。

三、利用hash处理问题

当数据量很大时,我们一些快速的方法已经不是多给点时间就能解决的,是压根解决不了,折半查找的方法在可接受的范围内是不可行的。我们来介绍一种神奇的方法,利用hash和位图实现常量时间确定邮件地址是否在S中。

1、过滤器初步设计

我们申请一个1GB的内存(虽然大了点,但现在的PC都顶得住了),1B共8位,1GB共有80亿位(实际应该为8X2^30=8,589,934,592位,但为了方便叙述,我们这里用80亿位)这个位图用B表示,B[i]表示位图的第i位;设计一个hash函数,将邮件地址映射到1-80亿的整数空间上。先将80亿位全部置为0,然后对S中的每一个邮件地址进行hash,hash得到一个整数k,就将第k位 置为1,即B[k]=1,如果hash函数设计得好,hash完S后,80亿的位图应该有10亿个(实际值比10亿小,后面会详细分析)位的值为1,当收到邮件时,对邮件地址进行hash,记hash得到的结果为p,如果B[p]=0,则邮件地址一定不再S中,即当作垃圾邮件过滤;如果B[p]=1,则邮件通过过滤,接收邮件。可以结合下图理解:

,

注意当B[p]=1时,我们并不是说新邮件地址一定在S中,而是说很可能在S中。B[p]=1只能说明S中一定有一个邮件地址URL,使得hash(URL)=p,而这不能保证其他垃圾邮件地址的hash值不等于p。B[p]=0说明S中不存在邮件地址URL,使得hash(URL)=p,从而新邮件地址一定不在S中。因此,被当作垃圾邮件过滤的邮件一定不包含合法的地址,而通过过滤的地址仍然有可能是垃圾邮件地址,大约有1/8(1/8=10亿/80亿,不过实际值比1/8小,后面会详细分析)的垃圾邮件通过过滤,1/8也称为伪阳率。

这样的方案直接上线还是有问题的,因为伪阳率比较高,我们来计算一下照这种方案我们接收的邮件中垃圾邮件的比率是多少。根据新闻报道全球80%的邮件是垃圾邮件,于是P(接收到的垃圾邮件/接收的邮件)=(1/8*80%)/(20%+1/8*80%)=1/3(33.33%),也就是说平均收三封邮件就有一封是垃圾邮件,这对用户来说是不能忍受的,方案必须优化,不过我们应该看到,我们在不漏掉任何一个合法邮件的前提下过滤了7/8的垃圾邮件,已经初显hash利器之锋芒了。

2、伪阳率分析

前面我们提到过伪阳率并不是1/8,它比1/8略小,现在我们从概率的角度来计算一下伪阳率的真实值。

先来看另外一个简单的例子,假设我们有m个飞镖、n个靶,一个射击高手(所谓高手就是无论怎么射击都不会脱靶的神人)把这m个飞镖一个接一个的射向这n个靶,假设一个飞镖击中每个耙的概率相等,问高手射击完之后,某一个靶上面一个飞镖也没有的概率是多少?这个计算并不难,对于任意的一个耙W,被某一个飞镖击中的概率P(耙W被某飞镖击中)=1/n,那么不被某一飞镖击中的概率P(耙W不被某飞镖击中)=1-1/n,射击m个飞镖可以看做是m次独立重复事件,于是P(耙W不被任何一个飞镖击中) = (1-1/n)^m,这也就是某一个耙上面一个飞镖也没有的概率。现在我们再问,某一个飞镖至少有一个飞镖的概率?有了上一步的分析,可以知道p(耙W上至少有一个飞镖)=1-P(耙W不被任何一个飞镖击中)=1- (1-1/n)^m。

现在回到我们之前的问题,我们的80亿个位相当于上例中的n个耙,10亿个合法邮件地址相当于m个飞镖,hash函数相当于射击高手,集合S经过hash后,某一位值为1(即至少被击中一次)的概率P=1-((1-1/8,000,000,000)^1,000,000,000),直接用计算器计算这个值是不现实的,因为1除以80亿已经下溢出为0,再进行10亿次累乘已经没有意义。这个值的计算需要用到极限的知识,伟大的数学家已经帮我们算好了,我们只需要套一下公式,还记得下面这个公式吗:

,

,

可以看到0.1175与我们初步估计的1/8=0.125相差并不大,所以我们之前用1/8分析是合理的。

p(某一位值为1)也就是伪阳率,即垃圾邮件被接收的概率,这里再解释一下为什么p(某一位值为1)就是垃圾邮件被接收的概率:我们收到一个新邮件,将地址hash为p,B[p]为1的概率即为我们接受邮件的概率,显然P(B[p]=1)=p(某一位值为1)。

3、优化过滤器,降低伪阳率

前面我们计算过了,按上面的方案,用户平均每接受3封邮件就有1封是垃圾邮件。我们对过滤器进行改进,设置k个hash函数h1,h2,...,hk,每一个hash函数的映射空间都是1-80亿的整数集。对S中的每一个邮件地址都在k个hash函数进行计算,记hash的结果为p1,p2,...,pk,则将对于位 置1,即B[pi]=1(i=1,2,..,k), 当新邮件发来时,我们对新邮件地址也在k个hash函数上计算,同样记hash的结果为p1,p2,...,pk,如果hash结果的所有位都为1,则接受邮件,否则新地址一定不再S中,当作垃圾邮件过滤。当k=2时的示意图如下:

,

跟1个hash函数一样,设置k个hash函数也不会漏掉任何一个合法邮件,而接受的邮件里仍然还是会有垃圾邮件,现在我们来计算此时的伪阳率,根据前面的分析,对单个hash函数的情况下,一个位为1的概率为P=1-e^(-m/n)。

现在有k个hash函数,相当于我们现在有k*m个飞镖,于是此时某一位为1的概率为P=1-e^(-k*m/n),但此时伪阳率不再等于p(某一位值为1),只有在k个hash结果所在位都为1的情况下我们才接收邮件,而P(k个hash结果所在位都为1)=(1-e^(-k*m/n))^k,因此伪阳率为(1-e^(-k*m/n))^k,当k=2时,伪阳率P=(1-e^(-1/4))^2=0.048929094,这个值比一个hash函数下的0.1175小了很多,那是不是伪阳率也越低呢,我们来看一下曲线图:

,

发现伪阳率随着k的增大先减小后增大,最后趋于1,最优的k值在5,6之间,但k取整数,因此k=6时伪阳率最小,即设置6个hash函数,可以得到最小的伪阳率,此时伪阳率的值为0.0216。一般情况下,最优值k=ln(2)*n/m,记住这个答案就可以了,如果感兴趣,可以参看下面的计算过程:

,

现在我们再来计算一下最优情况下k=6时,接收到的垃圾邮件在接收的邮件中的比例 P(接收到的垃圾邮件/接收的邮件)=80%*0.0216/(20%+80%*0.0216)=0.077490775=1/13,即平均每接收13封邮件有一封是垃圾邮件,我感觉这跟我的邮箱情况差不多,达到了用户可以承受的范围。

如果我们申请2G的内存,那么我们有160亿位,k=ln(2)*n/m=ln(2)*16=11.09,即k=10,此时伪阳率p=0.0004587, P(接收到的垃圾邮件/接收的邮件)=80%*0.0004587/(20%+80%*0.0004587)=0.00183144=1/546,也就是说平均接收546封邮件才收到一封垃圾邮件,这已经完全符合业务要求了,要知道这个方案处理速度很快,只需要计算几个hash函数,然后查位图,可在线计算(当然必须提前hash映射S)。

这个多个hash函数的顾虑器称为布隆过滤器(Bloom Filter)。

当有新的合法邮件添加时,将新合法邮件地址添加到S中,并进行k次hash,并将对应位置为1,这样新的合法邮件就不会被过滤,当新合法邮件添加到一定数量时,需要重新计算k,重新hash一遍S。

事实上,更多的垃圾邮件过滤是基于邮件内容的,可以在我们的过滤器过滤之后,进行自然语言处理内容分析过滤,我们的过滤器以及过滤了绝大部分垃圾邮件了。

我们见证了hash了处理海量数据的威力,这只是一个例子,相信大家可以在其他地方也能用的。

最后,我想说,终于发现以前的数学分析、高等代数、概率论有用了,不是吗?

参考资料:

[1].Anand Rajaraman, Jeffrey davaid UIIman. Mining of Massive Datasets. Cambridge University Presss 2012.

[2].维基百科.e (数学常数).https://zh.wikipedia.org/wiki/E_(%E6%95%B0%E5%AD%A6%E5%B8%B8%E6%95%B0). 2013.5.27

[3].Jure Leskovec.Stanford CS246 Mining Massive Data Sets.http://www.stanford.edu/class/cs246/.2013(很好的一门课,推荐)

[4].维基百科.Email spam.https://en.wikipedia.org/wiki/Email_spam.2013.6.21

海量数据处理--hash和bit-map,,

海量数据处理--hash和bit-map


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 原理:dismiss再弹出,把dialog设为全局对象。if(dialog!null&&dialog.isShowing()&&!(Activity.)isFinishing()) ... [详细]
  • HTML5网页模板怎么加百度统计?
    本文介绍了如何在HTML5网页模板中加入百度统计,并对模板文件、css样式表、js插件库等内容进行了说明。同时还解答了关于HTML5网页模板的使用方法、表单提交、域名和空间的问题,并介绍了如何使用Visual Studio 2010创建HTML5模板。此外,还提到了使用Jquery编写美好的HTML5前端框架模板的方法,以及制作企业HTML5网站模板和支持HTML5的CMS。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
author-avatar
hy11011_847
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有