数据结构与算法_大数据查重问题解决方法_布隆过滤器

介绍布隆过滤器特点和应用场景。

布隆过滤器

在内存有所限制的情况下(如上面的面试问题),快速判断一个元素是否在一个集合(容器)当中,除了用位图法,还可以使用布隆过滤器 。哈希表比较占用内存,位图法又不适用于数据少且最大值较大的情况,布隆过滤器结合了哈希表和位图法的优点。
布隆过滤器特点:

  • 1 布隆过滤器由一个位数组+k个哈希函数构成。
  • 2 布隆过滤器有一定错误率。布隆过滤器判断一个元素不在集合中,那么该元素一定不在集合中;布隆过滤器判断一个元素在集合中,那么该元素有可能在集合中,有可能不在,有个典型的应用场景就是过滤非法网站
  • 3 布隆过滤器的错误查找率与位数组大小以及哈希函数有关系,有相应的计算公式。
  • 4 Bloom Filter过滤器默认只支持add增加和query查询操作,不支持delete删除操作。
    增加一个元素:
  • 1 经过k个哈希函数计算,得到bitmap位数组里面的一组位的序号,如 int idx1 = BKDRHash(str) % bitSize_;
  • 2 把相应的位置成1,bitMap_[index] |= (1 << offset);;
    搜索一个元素:
  • 1 经过k个哈希函数计算,得到bitmap位数组里面的一组位的序号;
  • 2 判断数组中上面几个位的值,如果全是1,证明key可能存在;如果有1个0,则证明key不在bloom filter中。
    Bloom filter能提供删除操作吗?
    不能删除,因为某个位可能多个数公用,所以布隆过滤器不能删除某个元素。

布隆过滤器使用场景:

场景1:提示过滤一些非法的网站,或者钓鱼网站等。
比如我们用浏览器访问某个网站时候,浏览器先判断该网站是否合法,判断的方法就是布隆过滤器。
将所有怀疑有问题的网站的URL添加到布隆过滤器中,当用户要访问网站时候,查找当前访问的网站是否在黑名单中,通过布隆过滤器计算哈希值,在位数组中根据哈希表判断,如果存在(可能有误),会提示当前网站有风险,禁止访问;如果URL不存在,那么该网址一定是白名单上合法网站,直接访问。

场景2:redis缓存中的应用
比如购物网站,客户查询某个商品时候,就用到了布隆过滤器。
在这里插入图片描述
service层查找key,查找方法用布隆过滤器,现在redis缓存中查找(内存IO),再次从DB中查找(磁盘IO);然后依次返回。

// 布隆过滤器
class BloomFilter
{
public:
	BloomFilter(int bitSize = 1471)   // 给定bitmap数组初始长度
		:bitSize_(bitSize)
	{
		bitMap_.resize(bitSize_ / 32 + 1); // resize将vector数组长度调整到bitSize_ / 32 + 1
	}
public:
	void setBit(const char *str)
	{
		// 计算k组哈希函数的值,k=3
		int idx1 = BKDRHash(str) % bitSize_;
		int idx2 = RSHash(str) % bitSize_;
		int idx3 = APHash(str) % bitSize_;

		// 把相应的idx1 idx2 idx3 这个位全部置1
		int index = 0;
		int offset = 0;

		index = idx1 / 32;     				 // 找到数组中索引
		offset = idx1 % 32;					// 找到索引对应的位(从左到右开始)
		bitMap_[index] |= (1 << offset); 	// 将数组中对应的位 置1操作

		index = idx2 / 32;
		offset = idx2 % 32;
		bitMap_[index] |= (1 << offset);

		index = idx3 / 32;
		offset = idx3 % 32;
		bitMap_[index] |= (1 << offset);
	}

	// 查询元素
	bool getBit(const char *str)
	{
		// 计算k组哈希函数的值
		int idx1 = BKDRHash(str) % bitSize_;
		int idx2 = RSHash(str) % bitSize_;
		int idx3 = APHash(str) % bitSize_;
	
		int index = 0;
		int offset = 0;

		index = idx1 / 32;
		offset = idx1 % 32;
		if (0 == (bitMap_[index] & (1 << offset)))
		{
			return false;
		}

		index = idx2 / 32;
		offset = idx2 % 32;
		if (0 == (bitMap_[index] & (1 << offset)))
		{
			return false;
		}

		index = idx3 / 32;
		offset = idx3 % 32;
		if (0 == (bitMap_[index] & (1 << offset)))
		{
			return false;
		}
		return true;
	}
private:
	int bitSize_;			// 位图长度
	vector<int> bitMap_;	// 位图数组
};

// 过滤url 
class BlackList
{
private:
	BloomFilter blockList_;

public:
	BlackList()
	{
	
	}
	void add(string url)
	{
		blockList_.setBit(url.c_str());
	}
	bool query(string url)
	{
		return blockList_.getBit(url.c_str());  // 即使是true,也未必包含某个元素
	}
};

int main()
{
	BlackList l1;
	l1.add("www.baidu.com");
	l1.add("www.360.com");
	l1.add("www.tencent.com");

	string url = "www.baidu.com";
	cout << l1.query(url) << endl;
	
	system("pause");
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值