• 布隆过滤器和hash函数应用


    1 布隆过滤器的实现

    1-1 布隆过滤器基础知识

    需求:不安全的网页黑名单包含100亿个黑名单网页,每个网页的URL最多占用64B,现在实现一个网页过滤系统,可以根据网页URL判断该网页是否在黑名单上。
    
    注意:
    1)允许有万分之一以下的判断失误率
    2)额外空间不超过30G 约等于 30 x 10^9 B
    
    分析:所有网页存储需要 64 x 10^10 B 即640G空间
    

    hash函数的基本特征

    1) 有无限的输入值区域
    2) 有限范围的输出区域S,因此传入相同的输入值,返回值相同,不同值,返回值也可能相同(无限对有限,也就是所谓的hash碰撞)
    3) 优秀hash函数应保证输出S分布均匀(相似的输入hash碰撞概率低)
    

    布隆过滤器的组成

    1)大小为m的bitMap(位数组)
    2)k个独立并优秀的hash函数,其输出区域S确保都大于等于m.
    

    总结:因此布隆过滤器的实现核心就是确定其位数组的大小m和hash函数的个数。

    更多关于布隆过滤器原理参考

    布隆过滤器的应用场景 布隆过滤器的原理介绍

    1-2 布隆过滤器的设计步骤

    step1:根据实际需求中输入的总数n,允许错误率p,按照公式计算bit数组的大小m
    step2:根据n,m的值,按照公式计算hash函数的个数k
    step3:根据hash函数个数k以及bit数组大小m,计算实际错误率确保满足需求。
    
    布隆过滤器bit数组大小m与输入总数关系

    \[m=-\frac{n \times \ln p}{(\ln 2)^{2}} \]

    n:布隆过滤器的输入总数
    p: 布隆过滤器允许的判断失误率
    

    实例

    n = 100亿 , p = 0.0001 ln2 = 0.693147 ln(0.0001) = -9.21034
    代入公式为约为:m = 19.19n
    即bit数组的大小m至少为19.19 x 100亿 bit 取整则 2000亿 bit = 25GB左右
    
    hash函数个数k的计算

    \[k=\ln 2 \times \frac{m}{n}=0.7 \times \frac{m}{n} \]

    实例: k = ln2 * 19.19 约等于 0.7*20 = 14 个hash函数
    
    布隆过滤真实失误率计算

    \[\left(1-e^{-\frac{n k}{m}}\right)^{k} \]

    由于之间采用向上取整(k与m的大小都留有余量),因此n=100亿,m=2000亿bit,k = 14,得到的错误率约为0.006%,
    小于需求的0.01%
    
    布隆过滤器公式的推导

    2 哈希函数应用

    2-1 有限内存统计大规模数据

    需求:有一个包含20亿个全是32位整数(4B)的大文件,找到其中出现次数最多的数
    内存限制:2GB
    

    基本思路

    hash表统计键值对,key是4B,value是4B(4B有符号整数能够表示20亿),因此每个键值对为8B
    最钟需要的存储为 8B*20亿 = 16x10^9B 约为16GB,显然超过2GB限制
    

    进阶思路

    目标:对文件进行切分,确保单个文件的数据量不超过内存限制。
    题目中文件存储需要16GB,因此可以将文件切分为16个小文件,每个小文件单独统计各个字符的分布。最后获得16个结果
    
    问题:为什么划分16个?
    目的是限制每个文件的大小为1GB,这样极端情况下即便每个文件的数字都各不相同,也至多占用2GB
    
    问题:hash函数如何设计?
    选择一个性能比较号的hash函数,输出值去模上目标文件数目
    
    问题:上面方法存在的问题?
    必须确保相同的数都在同一个文件内部,如果数据分布非常不均匀,会存在某个区间的映射的数字超过1GB,这样该如何处理?
    
    
    极端情况如何处理?
    1)20亿个数都不同   2)20亿个数都相同  3) 9亿9999万个数相同,剩余的数也相同。
    获取:每个小文件中出现频率最高的数
    个人思路:
    1)用bitMap先统计不同的数字个数(如果不同数据个数使用hashmap能够承载的话,直接用hashmap统计)
    2)可以采用基数排序的方式,比如本题中可以使用2个位数对20取模的方式将文件均匀分配到各个文件,需要进行16次遍历
    3)排完序再顺序遍历的统计出现次
    

    2-2 海量数据TopK问题(摘录)

    针对top k类问题,通常比较好的方案是【分治+trie树/hash+小顶堆】,即先将数据集按照hash方法分解成多个小数据集,然后使用trie树或者hash统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出频率最高的前K个数,最后在所有top K中求出最终的top K。
    
    结合限制条件考虑:
    
    1 单机+单核+足够大内存
    
    设每个查询词平均占8Byte,则10亿个查询词所需的内存大约是10^9*8=8G内存。如果你有这么大的内存,直接在内存中对查询词进行排序,顺序遍历找出10个出现频率最大的10个即可。这种方法简单快速,更加实用。当然,也可以先用HashMap求出每个词出现的频率,然后求出出现频率最大的10个词。
    
    2 单机+多核+足够大内存
    
    这时可以直接在内存中实用hash方法将数据划分成n个partition,每个partition交给一个线程处理,线程的处理逻辑是同1类似,最后一个线程将结果归并。
    
    该方法存在一个瓶颈会明显影响效率,即数据倾斜,每个线程的处理速度可能不同,快的线程需要等待慢的线程,最终的处理速度取决于慢的线程。解决方法是,将数据划分成c*n个partition(c>1),每个线程处理完当前partition后主动取下一个partition继续处理,直到所有数据处理完毕,最后由一个线程进行归并。
    
    3 单机+单核+受限内存
    
    这种情况下,需要将原数据文件切割成一个一个小文件,如,采用hash(x)%M,将原文件中的数据切割成M小文件,如果小文件仍大于内存大小,继续采用hash的方法对数据文件进行切割,直到每个小文件小于内存大小,这样,每个文件可放到内存中处理。采用1的方法依次处理每个小文件。
    
    4 多机+受限内存
    
    这种情况下,为了合理利用多台机器的资源,可将数据分发到多台机器上,每台机器采用3中的策略解决本地的数据。可采用hash+socket方法进行数据分发。
    
    从实际应用的角度考虑,1~4的方案并不可行,因为在大规模数据处理环境下,作业效率并不是首要考虑的问题,算法的扩展性和容错性才是首要考虑的。算法应该具有良好的扩展性,以便数据量进一步加大(随着业务的发展,数据量加大是必然的)时,在不修改算法框架的前提下,可达到近似的线性比;算法应该具有容错性,即当前某个文件处理失败后,能自动将其交给另外一个线程继续处理,而不是从头开始处理。
    
    Top k问题很适合采用MapReduce框架解决,用户只需编写一个map函数和两个reduce 函数,然后提交到Hadoop(采用mapchain和reducechain)上即可解决该问题。对于map函数,采用hash算法,将hash值相同的数据交给同一个reduce task;对于第一个reduce函数,采用HashMap统计出每个词出现的频率,对于第二个reduce 函数,统计所有reduce task输出数据中的top k即可。
    

    参考资料

    linux文件大小

    海量数据TopK问题

  • 相关阅读:
    jquery加入购物车飞入的效果
    jQuery点击div其他地方隐藏div
    移动对meta的定义
    ZOJ
    博弈dp入门 POJ
    ZOJ 2967计算几何+单调栈
    牛客训练41D最小相似度bfs
    球的体积并
    二进制上的数位dpPOJ 3252
    数位dp入门 HDU 2089 HDU 3555
  • 原文地址:https://www.cnblogs.com/kfcuj/p/16199612.html
Copyright © 2020-2023  润新知