首页 > 其他分享 >BloomFilter布隆过滤器的使用

BloomFilter布隆过滤器的使用

时间:2022-10-10 10:33:59浏览次数:54  
标签:哈希 URL 布隆 字符串 BitSet str 过滤器 BloomFilter

布隆过滤器适合大数据判重的场景,如网络爬虫中判断一个URL是否已经爬取过,判断一个用户是否在黑名单中,判断一个邮件是否是垃圾邮件,等等。
优点:占用空间小,效率高,简而言之,就是以正确率换空间和时间。
缺点:有一定的误判率,一个URL经过布隆过滤器判断没爬取过,那么一定没爬取过,一个URL经过布隆过滤器判断爬取过,可能并没有爬取过,这种情况会有误判。
布隆过滤器本身是基于位图的,是对位图的一种改进,位图在java中的实现就是BitSet。

 

 

场景场景:

假设我们要写一个爬虫程序。由于网络间的链接错综复杂,蜘蛛在网络间爬行很可能会形成“环”,爬虫就会进入一个无限怪圈,找不到出路,程序出现崩溃。

所以为了避免形成“环”,就需要知道蜘蛛已经访问过那些URL,也就是如何判重。

给一个URL,怎样知道蜘蛛是否已经访问过呢?按照我们的常识,就会有如下几种方案:

    将访问过的URL保存到数据库,数据库管理系统可以为你去重。用Set将访问过的URL保存起来。那只需接近O(1)的代价就可以查到一个URL是否被访问过了。URL经过MD5或SHA-1等单向哈希后再保存到Set或数据库。Bit-Map方法。建立一个BitSet,将每个URL经过一个哈希函数映射到某一位。

    方法1~3都是将访问过的URL完整保存,方法4则只标记URL的一个映射位。

以上方法在数据量较小的情况下都能完美解决问题,但是当数据量变得非常庞大时问题就来了。

    方法1的缺点:数据量变得非常庞大后关系型数据库查询的效率会变得很低。而且每来一个URL就启动一次数据库查询是不是太小题大做了?
    方法2的缺点:太消耗内存。随着URL的增多,占用的内存会越来越多。就算只有1亿个URL,每个URL只算50个字符,至少需要5GB内存,还不包括Set数据结构中的内存浪费。
    方法3的缺点:由于字符串经过MD5处理后的信息摘要长度只有128Bit,SHA-1处理后也只有160Bit,因此方法3比方法2节省了好几倍的内存。
    方法4的缺点:消耗内存是相对较少的,但缺点是单一哈希函数发生冲突的概率太高。

若要降低冲突发生的概率到1%,有种办法就是就要将BitSet的长度设置为URL个数的100倍。

假设一亿条URL,就得把BitSet长度设为100亿,过于稀疏也是很费内存的

    实质上上面的算法都忽略了一个重要的隐含条件:允许小概率的出错,不一定要100%准确!
    也就是说少量url实际上没有没网络爬虫访问,而将它们错判为已访问的代价是很小的——大不了少抓几个网页呗。

Bloom Filter 算法原理

方法四的致命缺点是冲突概率高,为了降低冲突的概念,Bloom Filter使用了多个哈希函数,而不是一个。

为什么可以降低呢?我们知道Hash函数有一定几率出现冲突,概率假设为 p1,我们知道p1是一个很小的几率,但是在数据量大之后冲突就会变多,也就是上面第四种方法的问题。
BoomFilter使用 多个Hash函数 分别冲突概率为 p2 p3 p4 p5 .... pn ,我们知道不同 Hash函数处理同一个字符串彼此独立,所以冲突概率通过乘法公式得到为: p1p2p3p4p5p6.....pn,是相当相当小的了


预操作


创建一个m位BitSet(C++自带,Python为bitarray),先将所有位初始化为0,然后选择k个不同的哈希函数。第i个哈希函数对字符串str哈希的结果记为h(i,str),且h(i,str)的范围是0到m-1 。



Add操作

下面是每个字符串处理的过程,首先是将字符串str“记录”到BitSet中的过程:

对于字符串str,分别计算h(1,str),h(2,str)…… h(k,str)。然后将BitSet的第h(1,str)、h(2,str)…… h(k,str)位设为1。


CHeck操作

根据上图,我们对每个字符串采用同样的算法。

下面是检查字符串str是否被BitSet记录过的过程:

    对于字符串str,分别计算h(1,str),h(2,str)…… h(k,str)。然后检查BitSet的第h(1,str)、h(2,str)…… h(k,str)位是否为1,若其中任何一位不为1则可以判定str一定没有被记录过。若全部位都是1,则“认为”字符串str存在。
    若一个字符串对应的Bit不全为1,则可以肯定该字符串一定没有被Bloom Filter记录过。(这是显然的,因为字符串被记录过,其对应的二进制位肯定全部被设为1了)


    但是若一个字符串对应的Bit全为1,实际上是不能100%的肯定该字符串被Bloom Filter记录过的。(因为有可能该字符串的所有位都刚好是被其他字符串所对应)这种将该字符串划分错的情况,称为wrong position。


Delete操作

字符串加入了就被不能删除了,因为删除会影响到其他字符串。实在需要删除字符串的可以使用Counting bloomfilter(CBF),这是一种基本Bloom Filter的变体,CBF将基本Bloom Filter每一个Bit改为一个计数器,这样就可以实现删除字符串的功能了。

考虑到BoomFilter上面的指标,总结一下有以下几个

    m : BitSet 位数
    n : 插入字符串个数
    k :hash函数个数
    当然,哈希函数也是影响的重要因素

从表格来看 m/n越大越准,k越大越准。


BloomFilter的实现


java中的Guava工具包提供了BloomFilter的实现。

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.1-jre</version>
</dependency>

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.util.ArrayList;
import java.util.List;

public class Client {

  public static void main(String[] args) {
    int size = 1_000_000;
    BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size);
    for (int i = 0; i < size; i++) {
      bloomFilter.put(i);
    }
    for (int i = 0; i < size; i++) {
      if (!bloomFilter.mightContain(i)) {
        System.out.println("有坏人逃脱了");
      }
    }
    List<Integer> list = new ArrayList<>(1000);
    for (int i = size + 10000; i < size + 20000; i++) {
      if (bloomFilter.mightContain(i)) {
        list.add(i);
      }
    }
    System.out.println("有误伤的数量:" + list.size());
  }

}

 


输出结果为



标签:哈希,URL,布隆,字符串,BitSet,str,过滤器,BloomFilter
From: https://www.cnblogs.com/l1pe1/p/16774764.html

相关文章

  • Qt 事件过滤器原理(installEventFilter函数)
    1、Qt实现事件过滤器的步骤如下:①、Qt调用voidQObject::installEventFilter(QObject*filterObj)把filterObj对象安装(或注册)为事件过滤器,filterObj也称为过滤器对象......
  • HBase(3/5)过滤器
    Hbase学习(三)HBase的基本API,包括增、删、改、查等。增、删都是相对简单的操作,与传统的RDBMS相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根据行键......
  • Redis实现布隆过滤器解析
    布隆过滤器原理介绍【1】概念说明1)布隆过滤器(BloomFilter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用......
  • Redis 缓存穿透, 缓存击穿, 缓存雪崩的解决方案与布隆过滤器
    缓存穿透解决方案设置空值布隆过滤器优点可以将存在的缓存,位置设置为1,然后当不存在的参数过来的时候,会匹配到0上,这样就会直接返回不存在缺点存......
  • 14_过滤器
    过滤器<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>过滤器</title><scripttype="text/javascript"src="../js/vue.......
  • 比较 Bloom 过滤器和标记化以匹配去识别的患者数据
    比较Bloom过滤器和标记化以匹配去识别的患者数据了解Datavant用于匹配数据的标记化Datavant的使命是连接全球医疗保健数据,以改善患者治疗效果,同时维护患者隐私。H......
  • Filter(过滤器)
    1.过滤器的概念和作用1.1概念: 滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求;在请求到达Servlet/JSP之前,过滤器截获请求;1.2.作用:在客户端的请求访......
  • 布隆过滤器
     什么是布隆过滤器布隆过滤器(BloomFilter),是1970年,由一个叫布隆的小伙子提出的,距今已经五十年了。它实际上是一个很长的二进制向量和一系列随机映射函数,二进制大家应该......
  • Asp.Net Core 过滤器
    前言    过滤器,从我们开始开发Asp.Net应用程序开始,就一直伴随在我们左右;Asp.NetCore提供多种类型的过滤器,以满足多种多样的业务应用场景;并且在Asp.NetCore本身......
  • [2core]中间件和过滤器
    概述 最近在尝试做将asp.netwebapi项目转移为asp.netcorewebapi项目的技术试验,今天开始测试认证授权、资源控制、Action与Result控制、以及异常控制的技术变化与请求......