这年轻人,在JAVA项目中使用布隆过滤器

createh52周前 (12-20)技术教程17

提要

布隆过滤器(Bloom Filter)相信大家都听说过,不了解的朋友可以参考我之前的文章《布隆过滤器简介》。那么在Java项目中怎样使用布隆过滤器呢,下面就简单介绍下。

一. 使用Guava中提供的布隆过滤器

Guava是一套Google开源的Java库,它提供了很多简化编程的工具类,其中就包括了布隆过滤器。

使用方式

  • 在项目中添加依赖
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>29.0-jre</version>
</dependency>
  • 代码示例
package com.example;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.nio.charset.Charset;

/**
 * 使用Guava提供的布隆过滤器
 */
public class GuavaBloomFilter {

    // 预计存储元素的个数
    private static final int expectedInsertions = 10000;
    // 误判率
    private static final double fpp = 0.03;

    public static void main(String[] args) {
        // 创建布隆过滤器
        BloomFilter<CharSequence> bloomFilter = BloomFilter.create(
                Funnels.stringFunnel(Charset.defaultCharset()), expectedInsertions, fpp);
        // 存入元素
        bloomFilter.put("张三");
        bloomFilter.put("李四");

        System.out.println("大约存储元素的个数:" + bloomFilter.approximateElementCount());

        // 检索元素
        System.out.println("检索张三是否存在:" + bloomFilter.mightContain("张三"));
        System.out.println("检索王五是否存在:" + bloomFilter.mightContain("王五"));
    }
}

注意:Guava提供的布隆过滤器只能应用在单体应用中,因为这种方式创建的过滤器是存储在应用内存中的,所以在分布式环境下不适用。


二. 使用Redis中加载的布隆过滤器模块

在分布式环境下,使用Redis存储布隆过滤器就是个不错的选择。从Redis4.0版本开始,可以通过加载Redis实验室提供的布隆过滤器模块,使Redis中具有布隆过滤器类型。

使用此种方式操作布隆过滤器有个必要的前提:Redis Server必须加载布隆过滤器模块。加载方法可以参考我之前的文章《Redis加载布隆过滤器模块》。

一般我们在Java项目中连接Redis时通常是使用Jedis客户端,但是目前Jedis中没有提供对Redis扩展模块的命令的封装,所以我们必须使用Redis实验室提供的专门操作扩展模块的客户端。

使用方式

  • 在项目中添加依赖
<dependency>
    <groupId>com.redislabs</groupId>
    <artifactId>jrebloom</artifactId>
    <version>2.1.0</version>
</dependency>
  • 代码示例
package com.example;

import io.rebloom.client.Client;
import io.rebloom.client.ClusterClient;
import redis.clients.jedis.HostAndPort;

import java.util.HashSet;
import java.util.Set;

/**
 * 使用Redis布隆过滤器模块
 */
public class RedisModuleBloomFilter {

    // 容量
    private static final long initCapacity = 10000L;
    // 误判率
    private static final double errorRate = 0.03;
    
    private static final String FILTER_NAME = "BF:name"

    public static void main(String[] args) {
        // 初始化客户端
        Client client = new Client("localhost", 6379);

//        // 初始化集群客户端
//        Set<HostAndPort> clusterNodes = new HashSet<>();
//        clusterNodes.add(new HostAndPort("localhost", 6379));
//        ClusterClient client = new ClusterClient(clusterNodes);

        // 创建布隆过滤器;该方法只能调用一次,如果同名过滤器已存在,将抛出异常
        client.createFilter(FILTER_NAME, initCapacity, errorRate);
        // 添加单个元素
        client.add(FILTER_NAME, "mark");
        // 添加多个元素
        client.addMulti(FILTER_NAME, "foo", "bar", "baz", "bat", "bag");

        // 检查元素是否存在
        System.out.println(client.exists(FILTER_NAME, "mark"));
        System.out.println(client.exists(FILTER_NAME, "foot"));
    }
}

三. 使用Redisson提供的基于Redis布隆过滤器

Redisson是一款功能强大且简单易用的Java语言的Redis客户端。

强烈建议没有使用过的朋友可以学习一下。GitHub地址:https://github.com/redisson/redisson。值得一提的是,该项目还提供了中文文档(https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95),这对英文不好的朋友可以说是很大的福音了。

使用Redisson客户端提供的布隆过滤器功能可以直接在Redis中创建及使用布隆过滤器,无需在Redis Server中加载扩展模块。

使用方式

  • 在项目中添加依赖
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.13.6</version>
</dependency>
  • 代码示例
package com.example;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 * 使用redisson布隆过滤器
 */
public class RedissonBloomFilter {

    // 预计存储元素的个数
    private static final long expectedInsertions = 10000L;
    // 误判率
    private static final double fpp = 0.03;
    
    private static final String FILTER_NAME = "BF:name";

    public static void main(String[] args) {
        // 创建redisson连接
        Config config = new Config();
        config.useSingleServer().setTimeout(1000000).setAddress("redis://localhost:6379");
        RedissonClient redissonClient = Redisson.create(config);

        // 创建布隆过滤器并初始化
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(FILTER_NAME);
        bloomFilter.tryInit(expectedInsertions, fpp);

        // 存入元素
        bloomFilter.add("张三");
        bloomFilter.add("李四");

        // 检索元素是否存在
        System.out.println(bloomFilter.contains("张三"));
        System.out.println(bloomFilter.contains("王五"));

        // 关闭连接
        redissonClient.shutdown();
    }
}

相关文章

在Java中如果对象的引用被设置为null,垃圾收集器应当如何工作?

在Java中,如果在程序初始化之初就将一个对象的引用设置为NULL。那么JVM的垃圾回收机制该如何工作呢?是不是就会立即释放该对象所占用的内存呢?答案是否定的,将一个对象设置为NULL,垃圾回收机制并...

Java判空,Optional和工具类真香?还是if(obj == null)更靠谱?

背景描述最近在开发项目时,我遇到了一个需要从 Hyperlink 对象中获取 link 属性的小需求。这个过程中我需要判断 Hyperlink 对象是否为 null,以防止出现空指针异常。面对这种情况...

关于Java String 类型转换时null的问题

开发中经常遇到从集合类List、Map中取出数据转换为String的问题,这里如果处理不好,经常会遇到空指针异常java.lang.NullPointerException,在此总结一下常用转换为St...

Java中当对象不再使用时,不赋值为null会导致什么后果?

前言许多Java开发者都曾听说过“不使用的对象应手动赋值为null“这句话,而且好多开发者一直信奉着这句话;问其原因,大都是回答“有利于GC更早回收内存,减少内存占用”,但再往深入问就回答不出来了。鉴...

避免Java中NullPointerException的Java技巧和最佳实践

欢迎关注头条号:Java小野猫Java中的NullPointerException是我们最经常遇到的异常了,那我们到底应该如何在编写代码是防患于未然呢。下面我们就从几个方面来入手,解决这个棘手的?问题...

MySQL数据库的表中 NULL 和 空值 到底有什么区别呢

浅谈 NULL 和 空值的区别NULL也就是在字段中存储NULL值空字符串值也就是字段中存储空字符('')我们来通过测试来看看 他们彼此的区别:1、占用空间区别mysql> se...