布隆过滤器(Bloom Filter)
一、什么是布隆过滤器
以前有过这种需求,抽象来说就是:两个集合S1和S2,相交,求如下ABC三部分分别有哪些元素?
做法是:构造两个map,遍历。数据量小还可以,数据量大的话,就不可以了。直到看到“布隆过滤器”这个概念
1.1 定义
Bloom Filter是1970年由Bloom提出的。它实际上是一个很长的二进制向量和一系列随机映射函数(Hash函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。Bloom Filter广泛的应用于各种需要查询的场合中,如Orocle的数据库,Google的BitTable也用了此技术。
1.2 特点
- 不存在漏报(False Negative),即某个元素在某个集合中,肯定能报出来。
- 可能存在误报(False Positive),即某个元素不在某个集合中,可能也被爆出来。
- 确定某个元素是否在某个集合中的代价和总的元素数目无关。
二、实现
2.1 java实现
import java.util.BitSet;
public class BloomFilter {
// 位数组bits,长度为m,初值置为0
// hash函数f,长度为k
// 集合S,长度为n
// 布隆过滤器的比特长度 2^25
private static final int DEFAULT_SIZE = 2 << 24;
// 这里要选取质数,能很好的降低错误率
private static final int[] seeds = { 3, 5, 7, 11, 13, 31, 37, 61 };
// 位数组
private static BitSet bits = new BitSet(DEFAULT_SIZE);
// hash函数
private static SimpleHash[] func = new SimpleHash[seeds.length];
public static void addValue(String value) {
// 将字符串value哈希为8个或多个整数,然后在这些整数的bit上变为1
for (SimpleHash f : func) {
bits.set(f.hash(value), true);
}
}
public static void add(String value) {
if (value != null) {
addValue(value);
}
}
public static boolean contains(String value) {
if (value == null) {
return false;
}
boolean ret = true;
for (SimpleHash f : func) {
// 这里其实没必要全部跑完,只要一次ret==false那么就不包含这个字符串
ret = ret && bits.get(f.hash(value));
if (!ret) {
return ret;
}
}
return ret;
}
public static void main(String[] args) {
System.out.println(DEFAULT_SIZE);
String value = "www..net";
// 初始化hash函数
for (int i = 0; i < seeds.length; i++) {
func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
}
add(value);
System.out.println(contains(value));
}
}
class SimpleHash {// 这玩意相当于C++中的结构体
private int cap;
private int seed;
public SimpleHash(int cap, int seed) {
this.cap = cap;
this.seed = seed;
}
public int hash(String value) {// 字符串哈希,选取好的哈希函数很重要
int result = 0;
int len = value.length();
for (int i = 0; i < len; i++) {
result = seed * result + value.charAt(i);
}
return (cap - 1) & result;
}
}
2.2 c++实现
/*http://www.cnblogs.com/dolphin0520/archive/2012/11/10/2755089.html*/
/*布隆过滤器简易版本 2012.11.10*/
#include<iostream>
#include<bitset>
#include<string>
#define MAX 2<<24
using namespace std;
bitset<MAX> bloomSet; //简化了由n和p生成m的过程
int seeds[7]={3, 7, 11, 13, 31, 37, 61}; //使用7个hash函数
int getHashValue(string str,int n) //计算Hash值
{
int result=0;
int i;
for(i=0;i<str.size();i++)
{
result=seeds[n]*result+(int)str[i];
if(result > 2<<24)
result%=2<<24;
}
return result;
}
bool isInBloomSet(string str) //判断是否在布隆过滤器中
{
int i;
for(i=0;i<7;i++)
{
int hash=getHashValue(str,i);
if(bloomSet[hash]==0)
return false;
}
return true;
}
void addToBloomSet(string str) //添加元素到布隆过滤器
{
int i;
for(i=0;i<7;i++)
{
int hash=getHashValue(str,i);
bloomSet.set(hash,1);
}
}
void initBloomSet() //初始化布隆过滤器
{
addToBloomSet("http://www.baidu.com");
addToBloomSet("http://www.cnblogs.com");
addToBloomSet("http://www.google.com");
}
int main(int argc, char *argv[])
{
int n;
initBloomSet();
while(scanf("%d",&n)==1)
{
string str;
while(n--)
{
cin>>str;
if(isInBloomSet(str))
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
}
return 0;
}
三、应用场景
四、参考
网上大部分文章都是从下面这几篇文章中摘抄的。