Java中的布隆过滤器,你知道吗?

开发 前端
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

原理

布隆过滤器(Bloom Filter)是1970年由伯顿·霍华德·布隆(Burton Howard Bloom)提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。

布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash Table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间越来越大。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为O(n)、O(logn)、O(1)。

布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。

图片图片

检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。

图片图片

接下来,我们看下在Java中怎么使用。

单机版:Guava

首先引入依赖:

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

然后使用Guava中的BloomFilter类开始实现:

@Test
public void testBloomFilter() {
    final List<String> itemsToInsert = Arrays.asList("apple", "banana", "cherry", "elderberry");

    // 创建布隆过滤器
    BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), 100, 0.01);
    // 当前元素数量为0
    Assertions.assertEquals(0, bloomFilter.approximateElementCount());

    // 向布隆过滤器中插入数据
    for (String item : itemsToInsert) {
        bloomFilter.put(item);
    }
    // 当前元素数量为4
    Assertions.assertEquals(4, bloomFilter.approximateElementCount());

    // 测试已插入的数据
    for (String item : itemsToInsert) {
        Assertions.assertTrue(bloomFilter.mightContain(item), "Item should be in the Bloom Filter: " + item);
    }

    // 测试未插入的数据
    final List<String> itemsNotInserted = Arrays.asList("grape", "orange", "peach", "quince", "raspberry");
    for (String item : itemsNotInserted) {
        Assertions.assertFalse(bloomFilter.mightContain(item), "Item should not be in the Bloom Filter: " + item);
    }
}

Guava实现的是单机版,虽然提供了文件写出的功能,可以将文件分发到分布式系统中,但是这种方式只能是补充。推荐只在单机场景中使用Guava的布隆过滤器。

如果想要在分布式服务中使用,可以选择Redission。

分布式版:Redission

引入依赖:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.11.5</version>
</dependency>

使用Docker在本地启一个Redis服务,用来验证:

docker run -d -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest

然后编码测试:

@Test
public void testBloomFilter() {
    // 使用Docker本地启动一个Redis服务用来测试:
    //  docker run -d -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest

    Config config = new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");

    // 生成key是 myBloomFilter 的存储
    // 会生成两个key,"myBloomFilter"、"{myBloomFilter}:config"
    // "myBloomFilter"是string类型,布隆过滤器的主存
    // "{myBloomFilter}:config"是hash结构,存储元信息,比如大小size、期望容量expectedInsertions、误报率falseProbability、使用的哈希函数数量hashIterations等。
    RBloomFilter<String> bloomFilter = Redisson.create(config)
            .getBloomFilter("myBloomFilter");

    // 初始化布隆过滤器,定义期望容量和误报率
    bloomFilter.tryInit(1000000, 0.01);

    // 准备一些测试数据
    final List<String> itemsToInsert = Arrays.asList("apple", "banana", "cherry", "elderberry");

    // 向布隆过滤器中插入数据
    for (String item : itemsToInsert) {
        bloomFilter.add(item);
    }

    // 测试已插入的数据
    for (String item : itemsToInsert) {
        Assertions.assertTrue(bloomFilter.contains(item), "Item should be in the Bloom Filter: " + item);
    }

    // 测试未插入的数据
    final List<String> itemsNotInserted = Arrays.asList("grape", "orange", "peach", "quince", "raspberry");
    for (String item : itemsNotInserted) {
        Assertions.assertFalse(bloomFilter.contains(item), "Item should not be in the Bloom Filter: " + item);
    }
}

使用Redission的RBloomFilter,会根据布隆过滤器名字在Redis中生成两个key,比如上面代码的名字是“myBloomFilter”,生成的配置为:

  • "myBloomFilter"是string类型,布隆过滤器的主存,用来存储二进制数组;
  • "{myBloomFilter}:config"是hash结构,存储元信息,比如大小size、期望容量expectedInsertions、误报率falseProbability、使用的哈希函数数量hashIterations等。
责任编辑:武晓燕 来源: 看山的小屋
相关推荐

2024-01-05 09:04:35

隆过滤器数据结构哈希函数

2024-09-18 10:08:37

2024-10-17 08:53:41

2024-03-15 11:21:22

布隆过滤器数据库数据

2023-01-31 08:19:53

二进制元素数量

2024-11-04 08:45:48

布隆过滤器元数据指纹值

2020-10-29 07:16:26

布隆过滤器场景

2019-03-22 15:15:25

Redis缓存击穿雪崩效应

2022-03-21 08:31:07

布隆过滤器Redis过滤器原理

2021-09-03 06:33:24

布隆过滤器高并发

2024-10-09 15:54:38

布隆过滤器函数

2024-09-25 17:44:08

2021-03-06 14:41:07

布隆过滤器算法

2023-04-26 08:32:45

Redis布隆过滤器

2023-07-06 10:15:38

布隆过滤器优化

2023-11-20 14:18:55

大数据布隆过滤器布谷鸟过滤器

2016-12-07 09:56:13

JavaFilter过滤器

2020-08-28 13:02:17

布隆过滤器算法

2024-04-03 15:55:06

布隆过滤器

2024-03-04 10:24:34

布隆过滤器C#代码
点赞
收藏

51CTO技术栈公众号