不同的数据结构有不同的适用场景和优缺点,你需要仔细权衡自己的需求之后妥善适用它们
什么是布隆过滤器
本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),布隆过滤器(BloomFilter)由一个很长的二进制向量和一系列抗碰撞的Hash函数组成, 可以用于快速判断一个元素是否在一个集合中。
优点:空间仅由二进制向量决定,并且查询时间远超一般算法(仅需计算k 个Hash函数的值);
缺点:有一定的错误识别率,并且一旦元素被添加到布隆过滤器中就很难再将该元素从布隆过滤器中删除。
特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
布隆过滤器算法原理
初始状态时,BloomFilter是一个长度为m 的比特数组(二进制向量),每一位都置为0。
把1个新元素x 添加进BloomFilter,对x 计算k 个散列函数哈希值(哈希值作为比特数组的下标),将比特数组中对应位设置为1。
判断元素y 是否存在于BloomFilter中,对y 计算k 个散列函数哈希值,若对应位置的位皆为1,则说明y 存在于BloomFilter中
我这里用到布隆过滤器学习记录一下,至于推导公式有兴趣的,自己查一下。
应用场景:大数据去重
在面试阿里、腾讯时经常会问到“如何对大数据进行去重”的类似问题,比如:给定2个文件,里面保存的是url,对这2个文件中的url进行去重。这里提供3种解题思路:
(1)把文件A切割成k 个小文件(使得内存可容忍,例如占1/2内存),把文件B切割成k 个小文件,先读入A的第1个小文件,依次与B的k 个小文件做去重比较,算法复杂度O(n^2)。
(2)遇到1个url时,计算Index = Hash(url) % m的值,将该url 写入到标号为Index 的小文件中,留意相同值的url会被写到同一个小文件中,以此去重,算法复杂度O(n)。
(3)先对文件A的url建立一个BloomFilter,在遍历文件B的url时判断是否存在于BloomFilter中,若是则删除,算法复杂度O(n),虽然具有一定错误识别率,但更节省空间,并且实际运行可能比方案(2)更快。
(注:在Linux中有特定命令可以完成2个文件的去重)
# 前提条件:两个文件不得有重复的行(即两个文件都要提前去重)
# uniq : 检查及删除文本文件中重复出现的行列。
# 语法:uniq[选项] 文件
# 最重要参数: 默认(去重) | -d(显重) | -u(删重)
# 1. 取出两个文件的并集
cat file1 file2 | sort | uniq >file3
# 2. 取出两个文件的交集
cat file1 file2 | sort | uniq -d >file3
# 3. 删除交集
cat file1 file2 | sort |uniq -u >file3
黑名单
比如邮件黑名单过滤器,判断邮件地址是否在黑名单中
排序(仅限于BitSet)
仔细想想,其实BitSet在set(int value)的时候,“顺便”把value也给排序了。
网络爬虫
判断某个URL是否已经被爬取过
K-V系统快速判断某个key是否存在
典型的例子有Hbase,Hbase的每个Region中都包含一个BloomFilter,用于在查询时快速判断某个key在该region中是否存在,如果不存在,直接返回,节省掉后续的查询。