什么是 BloomFilter(布隆过滤器)

布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。主要用于判断一个元素是否在一个集合中。通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,这个时候往往我们都是采用 Hashmap,Set 或者其他集合将数据保存起来,然后进行对比判断,但是如果元素很多的情况,我们如果采用这种方式就会非常浪费空间。这个时候我们就需要 BloomFilter 来帮助我们了。

BloomFilter 原理

BloomFilter 是由一个固定大小的二进制向量或者位图(bitmap)和一系列(通常好几个)映射函数组成的。布隆过滤器的原理是,当一个变量被加入集合时,通过 K 个映射函数将这个变量映射成位图中的 K 个点,把它们置为 1。查询某个变量的时候我们只要看看这些点是不是都是 1 就可以大概率知道集合中有没有它了,如果这些点有任何一个 0,则被查询变量一定不在;如果都是 1,则被查询变量很可能在。注意,这里是可能存在,不一定一定存在!这就是布隆过滤器的基本思想。

如下图所示,字符串 “ziyou” 在经过四个映射函数操作后在位图上有四个点被设置成了 1。当我们需要判断 “ziyou” 字符串是否存在的时候只要在一次对字符串进行映射函数的操作,得到四个 1 就说明 “ziyou” 是可能存在的。

为什么说是可能存在,而不是一定存在呢?那是因为映射函数本身就是散列函数,散列函数是会有碰撞的,意思也就是说会存在一个字符串可能是 “ziyou01” 经过相同的四个映射函数运算得到的四个点跟 “ziyou” 是一样的,这种情况下我们就说出现了误算。另外还有可能这四个点位上的 1 是四个不同的变量经过运算后得到的,这也不能证明字符串 “ziyou” 是一定存在的,如下图框出来的 1 也可能是字符串“张三”计算得到,同理其他几个位置的 1 也可以是其他字符串计算得到。

1.2 特性

所以通过上面的例子我们就可以明确

一个元素如果判断结果为存在的时候元素不一定存在,但是判断结果为不存在的时候则一定不存在。

布隆过滤器可以添加元素,但是不能删除元素。因为删掉元素会导致误判率增加。

02、使用场景

2.1、网页 URL 去重

我们在使用网页爬虫的时候(爬虫需谨慎),往往需要记录哪些 URL 是已经爬取过的,哪些还是没有爬取过,这个时候我们就可以采用 BloomFilter 来对已经爬取过的 URL 进行存储,这样在进行下一次爬取的时候就可以判断出这个 URL 是否爬取过。

2.2、黑白名单存储

工作中经常会有一个特性针对不同的设备或者用户有不同的处理方式,这个时候可能会有白名单或者黑名单存在,所以根据 BloomFilter 过滤器的特性,我们也可以用它来存在这些数据,虽然有一定的误算率,但是在一定程度上还是可以很好的解决这个问题的。

2.3、小结

除了上面说的两种场景,其实还有很多场景,比如热点数据访问,垃圾邮件过滤等等,其实这些场景的统一特性就是要判断某个元素是否在某个集合中,原理都是一样的。

03、代码实践

3.1、自己实现

package com.test.pkg;

import java.util.BitSet;

/**

*

* Function:

* Author:@author ziyou

* Date:2019-10-23 23:21

* Desc:

*/

public class BloomFilterTest {

/**

* 初始化布隆过滤器的 bitmap 大小

*/

private static final int DEFAULT_SIZE = 2 << 24;

/**

* 为了降低错误率,这里选取一些数字作为基准数

*/

private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};

/**

* 设置 bitmap

*/

private static BitSet bitset = new BitSet(DEFAULT_SIZE);

/**

* 设置 hash 函数数量

*/

private static HashFunction[] functions = new HashFunction[seeds.length];

/**

* 添加数据

*

* @param value 需求加入的值

*/

public static void put(String value) {

if (value != null) {

for (HashFunction f : functions) {

//计算 hash 值并修改 bitmap 中相应位置为 true

bitset.set(f.hash(value), true);

}

}

}

/**

* 判断相应元素是否存在

*

* @param value 需要判断的元素

* @return 结果

*/

public static boolean check(String value) {

if (value == null) {

return false;

}

boolean ret = true;

for (HashFunction f : functions) {

ret = bitset.get(f.hash(value));

//一个 hash 函数返回 false 则跳出循环

if (!ret) {

break;

}

}

return ret;

}

public static void main(String[] args) {

String value = "test";

for (int i = 0; i < seeds.length; i++) {

functions[i] = new HashFunction(DEFAULT_SIZE, seeds[i]);

}

put(value);

System.out.println(check("value"));

}

}

class HashFunction {

private int size;

private int seed;

public HashFunction(int size, int seed) {

this.size = size;

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);

}

int r = (size - 1) & result;

return (size - 1) & result;

}

}

上面我们自己写了一个简单的 BloomFilter ,通过 put 方法录入数据,通过 check 方法判断元素是否存在,基本能实现功能,代码中注释也写的很清楚,但是自己实现必定效率不高,所以下面我们看下业内大佬帮我们已经实现好的 BloomFilter。

2.4、Guava 中的 BloomFilter

package com.test.pkg;

import com.google.common.hash.BloomFilter;

import com.google.common.hash.Funnels;

/**

*

* Function:

* Author:@author ziyou

* Date:2019-10-24 00:17

* Desc:

*/

public class BloomFilterTest02 {

public static void main(String[] args) {

BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 100000, 0.01);

for (int i = 0; i < 100000; i++) {

bloomFilter.put(i);

}

System.out.println(bloomFilter.mightContain(1));

System.out.println(bloomFilter.mightContain(2));

System.out.println(bloomFilter.mightContain(3));

System.out.println(bloomFilter.mightContain(100001));

}

}

Guava 中已经帮我们实现好了 BloomFilter 的代码,我们只需要在使用的地方调用就好。

这里我们简单解释一下构造方法中的后面两个参数,一个是预计包含的数据量,一个是允许的误差值。代码中会根据我们填入的这两个值,自动帮我们计算出数组的大小,以及需要的散列函数个数,如下图。更多详细的内容,读者可以自行去查看源码,我们这里就不介绍了。

04、总结

这篇文章给大家介绍了 BloomFilter,一个用来判断元素是否存在与某个集合的高效方法,可以在我们日常的工作中运用起来,结合日常工作的场景,可以进行选择。

原文发于:《Java极客技术》公众号,作者:ziyou

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解相关推荐

  1. 【华为云计算产品系列】eBackup云备份原理及实战详解

    [华为云计算产品系列]eBackup云备份原理及实战详解 1. 基础概念 2. eBackup的组网方式 2.1. LAN-Base 2.2. LAN-Free 2.3. Server-Free 3. ...

  2. java linkedlist实例_Java Linkedlist原理及实例详解

    这篇文章主要介绍了Java Linkedlist原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定义:linkedlist属于链表结构 ...

  3. redis队列优先级java实现_Redis 实现队列原理的实例详解

    Redis 实现队列原理的实例详解 场景说明: ·用于处理比较耗时的请求,例如批量发送邮件,如果直接在网页触发执行发送,程序会出现超时 ·高并发场景,当某个时刻请求瞬间增加时,可以把请求写入到队列,后 ...

  4. C++后端程序员必须彻底搞懂Nginx,从原理到实战详解

    本文首先介绍 Nginx 的反向代理.负载均衡.动静分离和高可用的原理,随后详解 Nginx 的配置文件,最后通过实际案例实现 Nginx 反向代理和负载均衡的具体配置.学会 Nginx ,一篇足够了 ...

  5. Redis缓存雪崩、穿透、击穿,布隆过滤器,分布式锁详解

    缓存雪崩 在某一个时间存在大量的缓存key失效 解决办法 1.有效期一直---->给每一个数据加上水机有效期 2.redis挂掉了----->使用redis集群,分摊key的存储 引出re ...

  6. java 匿名内部类 参数_Java匿名内部类原理与用法详解

    本文实例讲述了Java匿名内部类原理与用法.分享给大家供大家参考,具体如下: 一 点睛 匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下: new 父类构造器(实参列表) | 实 ...

  7. SNMP学习笔记之SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  8. SNMP 原理与实战详解

    文章转自http://freeloda.blog.51cto.com/2033581/1306743 大纲 一.什么是SNMP 二.SNMP背景 三.SNMP结构概述 四.SNMP支持的网管操作 五. ...

  9. 布隆过滤器原理和基于BloomFilter的误判率展示

    布隆过滤器 布隆过滤器原理 布隆过滤器是由n个Hash函数和一个二进制数组组成. 如图所示(参考,hash函数可以多个) 1.保存操作 发来一个请求数据hello 对数据hello经过三次hash运算 ...

最新文章

  1. AE 动画直接变原生代码:Airbnb 发布开源动画库 Lottie
  2. c 异步中断服务器连接,异步连接和断开与epoll(Linux)
  3. 2019年软件测试现状调查
  4. HDU2025 查找最大元素
  5. SAP透明工厂和弹性制造的原型mockup - SAP 工业 4.0 的一个尝试
  6. solr 启动、停止
  7. 4.6.3 内表数据处理
  8. dbcc dbreindex server sql_SQL Server性能的提高,可通过DBCC DBREINDEX重建索引
  9. android actionbar tab,ActionBar+Fragment实现Tab
  10. 50余家光伏企业竞标混战:0.52元最低价仍有利润!
  11. 想成长为一名年薪50万+的实战型架构师?必掌握这7大实战技能经验
  12. .ipynb文件的使用问题
  13. 【优化预测】基于matlab差分算法优化ANN预测【含Matlab源码 151期】
  14. VS之sonar插件安装
  15. Python 计算思维训练——SAR图像处理
  16. vvc代码阅读 encodeCtus()
  17. 日本战国武将绰号与称号一览表
  18. Leedcode 875. 爱吃香蕉的珂珂
  19. 栈内存与堆内存的简单理解
  20. IOS开发之——AFN-网络状态监控(04)

热门文章

  1. Akka Notes –演员记录和测试
  2. MapReduce算法–顺序反转
  3. 从Java 8启动项目拼图?
  4. Java EE 6示例– Galleria –第3部分
  5. Hadoop模式介绍-独立,伪分布式,分布式
  6. MySQL查询语句后面加上“\G”,提示 ERROR: No query specified
  7. Linux 命令之 deluser -- 删除用户
  8. Linux 系统服务管理(启动服务/停止服务/重启服务)的命令 - chkconfig/service/systemctl
  9. idea连接mysql数据库时连接显示错误caching_sha2_password
  10. 如何卸载linux中的docker,linux centos7 安装、卸载docker