基于Redis实现的布隆过滤器

2023-05-16

一、RedisTemplate
1、首先将guava实现的本地的布隆过滤器的算法代码拿过来

/**
 * 算法过程:
 * 1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
 * 2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
 * 3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
 * 4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。
 **/
public class BloomFilterHelper<T> {
    private int numHashFunctions;

    private int bitSize;

    private Funnel<T> funnel;

    public BloomFilterHelper(Funnel<T> funnel, int expectedInsertions, double fpp) {
        Preconditions.checkArgument(funnel != null, "funnel不能为空");
        this.funnel = funnel;
        // 计算bit数组长度
        bitSize = optimalNumOfBits(expectedInsertions, fpp);
        // 计算hash方法执行次数
        numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, bitSize);
    }

    public int[] murmurHashOffset(T value) {
        int[] offset = new int[numHashFunctions];

        long hash64 = Hashing.murmur3_128().hashObject(value, funnel).asLong();
        int hash1 = (int) hash64;
        int hash2 = (int) (hash64 >>> 32);
        for (int i = 1; i <= numHashFunctions; i++) {
            int nextHash = hash1 + i * hash2;
            if (nextHash < 0) {
                nextHash = ~nextHash;
            }
            offset[i - 1] = nextHash % bitSize;
        }

        return offset;
    }

    /**
     * 计算bit数组长度
     */
    private int optimalNumOfBits(long n, double p) {
        if (p == 0) {
            // 设定最小期望长度
            p = Double.MIN_VALUE;
        }
        return (int) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
    }

    /**
     * 计算hash方法执行次数
     */
    private int optimalNumOfHashFunctions(long n, long m) {
        return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
    }
}

2、结合redis将数据存到bitMap中

public class BloomRedisService {

    private RedisTemplate<String, Object> redisTemplate;

    private BloomFilterHelper bloomFilterHelper;

    public void setBloomFilterHelper(BloomFilterHelper bloomFilterHelper) {
        this.bloomFilterHelper = bloomFilterHelper;
    }

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 根据给定的布隆过滤器添加值
     */
    public <T> void addByBloomFilter(String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        for (int i : offset) {
            redisTemplate.opsForValue().setBit(key, i, true);
        }
    }

    /**
     * 根据给定的布隆过滤器判断值是否存在
     */
    public <T> boolean includeByBloomFilter(String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        for (int i : offset) {
            if (!redisTemplate.opsForValue().getBit(key, i)) {
                return false;
            }
        }
        return true;
    }
}

3、可以拦截查询方法,对查询数据是否存在进行处理,如果存在则继续,否则不执行查询操作

@Slf4j
public class BloomFilterInterceptor implements HandlerInterceptor {

    @Autowired
    private BloomRedisService bloomRedisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String currentUrl = request.getRequestURI();
        PathMatcher matcher = new AntPathMatcher();
        //解析出pathvariable
        Map<String, String> pathVariable = matcher.extractUriTemplateVariables("/pms/productInfo/{id}", currentUrl);
        //布隆过滤器存储在redis中
        if(bloomRedisService.includeByBloomFilter(RedisKeyPrefixConst.PRODUCT_REDIS_BLOOM_FILTER,pathVariable.get("id"))){
            return true;
        }

        /**
         * 存储在本地jvm布隆过滤器中
         */
        /*if(LocalBloomFilter.match(pathVariable.get("id"))){
            return true;
        }*/

        /*
         * 不在本地布隆过滤器当中,直接返回验证失败
         * 设置响应头
         */
        response.setHeader("Content-Type","application/json");
        response.setCharacterEncoding("UTF-8");
        String result = new ObjectMapper().writeValueAsString(CommonResult.validateFailed("产品不存在!"));
        response.getWriter().print(result);
        return false;

    }

}

二、Redission
Redission对Redis做了很多封装,除了常见的分布式锁之外,对布隆过滤器也同样有实现,简单好用

public class RedissonBloomFilter {
 
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://ip:port");
        //构造Redisson
        RedissonClient redisson = Redisson.create(config);
 
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("phoneList");
        //初始化布隆过滤器:预计元素为100000000L,误差率为3%
        bloomFilter.tryInit(100000000L,0.03);
		//插入数据
        bloomFilter.add("aa");
 
        //判断下面号码是否在布隆过滤器中
        System.out.println(bloomFilter.contains("bb"));//false
        System.out.println(bloomFilter.contains("aa"));//true
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Redis实现的布隆过滤器 的相关文章

随机推荐

  • sift = cv2.xfeatures2d.SIFT_create报错,解决

    本人原因opencv版本过高 xff0c 回退版本解决 先卸载原有opencv版本 pip uninstall opencv python pip uninstall opencv contrib python 回退版本到3 4 2 17解
  • CentOS 7.9上lightdm+ICEWM 桌面的配置+XManager远程

    IceWM是X Window系统的窗口管理器 IceWM的目标是速度 xff0c 简单 xff0c 并且不妨碍用户 它带有一个带寻呼机的任务栏 xff0c 全局键绑定和每窗口键绑定和动态菜单系统 应用程序窗口可以通过键盘和鼠标进行管理 窗口
  • windows下使用powershell 操作服务器进行上传或下载

    1 上传文件使用scp命令 43 本地路径 43 服务器用户名称 64 服务器Ip xff1a 上传路径 2 下载文件到本地 使用scp命令 43 服务器用户名称 64 服务器Ip xff1a 文件路径 43 下载到本地的路径 最后的点表示
  • 佛系解决 DataBinding 无法生成 Activity****Binding 类

    起初呢 xff0c ActivityMainBinding 该类始终无法生成 于是确定一下几个地方 build gradle android dataBinding enabled 61 true 布局文件名称 lt layout gt l
  • 宇宙最强pyqt5的安装(一)!!!

    前期准备工作 xff1a pythonIDE3 5以上版本开发环境pycharm编程知识熟悉python基本语法 在线安装pyqt5 安装sip C Users xxx gt pip install sip Collecting sip D
  • Win10下部署TensorFlow以及一些避坑小指南

    第一步 xff0c 下载Anaconda3 Anaconda官网目前最新的版本是Python3 6的 xff0c 想要历史版本的 xff0c 去下面的网站下载 xff1a https repo continuum io archive 我们
  • SpringBoot如何整合邮箱服务实现登录验证功能

    写在前面 这里主要讲解大致思路 详细代码 xff08 目前部分功能还在开发完善中 xff09 请见这里 如果个人用户还是想白嫖短信服务的话 xff0c 可以看看我的这篇博客 一 开启 POP3 SMTP服务 获得的授权码 这里以qq邮箱为例
  • 手动创建和挂载SWAP分区

    手动创建和挂载SWAP分区 在安装系统的时候很难决定多大的交换空间 xff0c 往往需要根据服务器实际负载 运行情况 以及未来可能应用来综合考虑 swap 分区的大小 xff0c 所以这里参考推荐最小 swap 大小更实际一些 xff1a
  • python中处理字符编码问题

    NO 1认识字符编码 GBK win默认中文字符编码是 xff1a GBK Unicode xff08 统一码 万国码 单一码 xff09 是计算机科学领域里的一项业界标准 xff0c 包括字符集 编码方案等 Unicode 是为了解决传统
  • python中if not的用法

    python中空的概念 xff1a 在python中 xff1a None False 0 空列表 空字典 空元祖 都相当于false coding utf 8 x 61 39 39 0 False None 1 x为真 故not x 为假
  • python实现文件上传下载的功能socket编程(基础版)

    环境介绍 xff1a 项目路径 xff1a 服务端执行过程 xff1a 客户端执行过程 xff1a 上传成功截图 xff1a 服务端代码 xff1a import socket file server 61 socket socket fi
  • -bash: java: command not found (Linux)

    原因 xff1a 安装jdk后没有配置环境变量 1 编辑配置文件 xff0c 配置环境变更 vim etc profile 在最下面添加 export JAVA HOME 61 usr local jdk8 export PATH 61 P
  • idea使用本地代码远程调试线上运行代码---windows环境

    场景 xff1a 今天在书上看了一个代码远程调试的方法 xff0c 自己本地验证了一下感觉十分不错 xff01 xff01 windows环境 xff1a 启动测试jar包 xff1a platform multiappcenter bas
  • anaconda:安装cuda和对应版本的cudnn

    复现别人论文的时候经常遇到不同的cuda版本 xff0c 可以使用anaconda创建虚拟环境 xff0c 并在不同的虚拟环境中配置对应的cuda版本 1 安装anaconda及虚拟环境使用 Anaconda多个python版本 xff08
  • Linux Server 种脚本自动执行

    在我们用python编写完脚本后 xff0c 时常需要定时运行我们的脚本 在这里 xff0c 我为大家介绍两种常用定时执行python脚本文件的方式 xff1a 第一种 xff1a crontab job 在Linux系统中可以通过设置cr
  • Tomcat9配置HTTP/2

    1 概述 Tomcat从Tomcat8的一些较新版本就支持HTTP 2了 xff0c Tomcat9直接支持 xff0c 本文首先讲述了相关HTTP 2的特性 xff0c 接着利用一个简单的开源工具mkcert生成证书并利用该证书配置HTT
  • SVN提交代码报错,怎么破?

    目录 SVN提交代码报错1 SVN提交被锁定 xff08 locked xff09 2 SVN提交已存在版本控制信息 xff08 is already under version control xff09 SVN提交代码报错 1 SVN提
  • Hive隐藏分割字符\001替换为可见字符

    Hive默认的分隔符是 001 xff0c 属于不可见字符 xff0c 这个字符在vi里是 A 一个文本0000 0 xff0c 直接cat内容如下 xff1a 320643204N2559613979 320828796N446323 3
  • 计算机毕业设计 HTML+CSS+JavaScript食品餐饮行业网站(10页)

    x1f380 精彩专栏推荐 x1f447 x1f3fb x1f447 x1f3fb x1f447 x1f3fb 作者简介 一个热爱把逻辑思维转变为代码的技术博主 x1f482 作者主页 主页 x1f680 获取更多优质源码 x1f393 w
  • 基于Redis实现的布隆过滤器

    一 RedisTemplate 1 首先将guava实现的本地的布隆过滤器的算法代码拿过来 span class token comment 算法过程 xff1a 1 首先需要k个hash函数 xff0c 每个函数可以把key散列成为1个整