布隆过滤器原理介绍和典型应用案例

整理自己过去使用布隆过滤器的应用案例和理解

基本介绍

        1970年由布隆提出的一种空间效率很高的概率型数据结构,它可以用于检索一个元素是否在一个集合中,由只存0或1的位数组和多个hash算法, 进行判断数据   【一定不存在或者可能存在的算法】

如果这些bit数组 有任何一个0,则被判定的元素一定不在;  如果都是1则被检元素很可能在

对比bitmap位图,布隆过滤器适合更多类型元素,通过hash值转换

原理:将元素添加到一个bitmap数组中,每个散列函数将元素映射到bitmap数组中的一个位置。如果该位置已经被占用,则将该位置置为1,否则置为0。当要查询一个元素是否存在时,只需要计算该元素的散列值,并检查bitmap数组中对应的位置是否已经被置为1。如果都是1,则该元素可能存在,否则肯定不存在。不存在的一定不存在,存在的不一定存在

优点:占用空间小,查询速度快,空间效率和查询时间都远远超过一般的算法。

缺点:有一定的误识别率,有一定的误识别率,即某个元素可能存在,但实际上并不存在。删除困难,因为无法确定某个位置是由哪个元素映射而来的。

 在线案例:Bloom Filters

布隆过滤器存在误判率,数组越小,所占的空间越小,误判率越高;如果要降低误判率,则数组越长,但所占空间越大
最大限度的避免误差, 选取的位数组应尽量大, hash函数的个数尽量多, 但空间占用的浪费和性能的下降
业务选择的时候, 需要误判率与bit数组长度和hash函数数量的平衡
布隆过滤器不能直接删除元素,因为所属的bit可能多个元素有使用
如果要删除则需要重新生成布隆过滤器,或者把布隆过滤器改造成带引用计数的方式 

应用场景

解决海量数据下非精确过滤的业务场景 

1)垃圾邮件解决方案(垃圾短信、黑名单同理)

        收集一组具有特定特征的垃圾邮件样本,这些样本可以是文本内容或其他特征,比如发件人、收件人等,将这些样本的特征信息进行哈希处理,并将处理后的结果存储在布隆过滤器中。接下来,当有新的电子邮件到达时,将该邮件的特征信息也进行哈希处理,并且与布隆过滤器中的信息进行比较。如果布隆过滤器中存在该邮件的特征信息,则判断该邮件为垃圾邮件;如果不存在,则判断该邮件为正常邮件

2)解决缓存穿透解决方案

        什么是缓存穿透(查询不存在数据),查询一个不存在的数据,由于缓存是不命中的,如发起为id为“-1”不存在的数据。如果从存储层查不到数据则不写入缓存,导致这个不存在的数据每次请求都要到存储层去查询,大量查询不存在的数据,可能DB就挂掉了,是黑客利用不存在的key频繁攻击应用的一种方式。

       方案就是将所有要【缓存的数据】经过处理后存储布隆过滤器中,即对应的bit上是1,当外部请求发起时,首先会把请求的参数通过哈希算法处理,获得相应的哈希值;根据哈希值计算出位数组中的位置。

如果全部计算的hash值对于的bit存储都是1,则表示数据在合理中,从缓存读出(缓存失效则从数据库中取出);

如果计算的hash值对于的bit存储存在一个是0或以上,则表示这条数据不合理,直接返回数据不存在,不查缓存和数据库,如果布隆过滤器认为值不存在,那么值一定是不存在的,无需查询缓存也无需查询数据库;

3)爬虫URL去重解决方案

        需求:大量的网页爬取,通过解析已经爬取页面中的网页链接,然后再爬取这些链接对应的网页,同一个网页链接有可能被包含在多个页面中,会导致爬虫在爬取的过程中,重复爬取相同的网页;

        方案:创建布隆过滤器,根据业务数据量设置位数组的大小,将位数组全部设置为0;
将每个URL地址通过哈希算法处理,获得相应的哈希值;
根据哈希值计算出位数组中的位置,将位数组中的位置设置为1;
当新的URL地址进入时,重复上述步骤计算出对应的位置,检查位数组中的位置是否为0,如果是0,则表示该URL地址一定没被爬取过;
如果URL地址不存在,经过爬虫处理后,则将其对应的位置设置为1,以表示该URL地址已经存在;
重复上述步骤,直到所有的URL地址都处理完毕,完成去重。

POM 依赖
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>


    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version>
    </dependency>

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

</dependencies>
 @Test
    public void testGeneUrl() {
        try{
            File file = new File("urls.txt");
            if (!file.exists()) {
                file.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖
            }
            FileOutputStream fos = new FileOutputStream(file, true);
            OutputStreamWriter osw = new OutputStreamWriter(fos);
            BufferedWriter bw = new BufferedWriter(osw);
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 5000000; i++) {
                String name = RandomStringUtils.randomAlphabetic(5);
                String fileName = "https://www." + name + ".com" + i + "\n";
                builder.append(fileName);
            }
            bw.write(String.valueOf(builder));
            bw.newLine();
            bw.flush();
            bw.close();
            osw.close();
            fos.close();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e2) {
            e2.printStackTrace();
        }
    }

//参数一: 指定布隆过滤器中存的是什么类型的数据,有 IntegerFunnel,LongFunnel,StringCharsetFunnel
//参数二: 预期需要存储的数据量
//参数三: 误判率,默认是 0.03
BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 5000000, 0.01);

 4)分库分表下手机号重复注册解决方案

        一般业务里面的partitionKey是不可变动的,所以不能用手机号作为分片键(换手机号需求是存在的),所以业务里面的分片键,多数是固定的业务id,比如user_id

创建布隆过滤器,根据业务数据量设置位数组的大小,将位数组全部设置为0;
把要注册的手机号通过通过哈希算法处理,获得相应的哈希值;
根据哈希值计算出位数组中的位置,如果对应的位数组中的位置有存在0,则一定是未注册的
如果经过多个hash函数处理,对应的位数组中都是1,则认为是注册过的
最后如果用户注册成功后,将位数组中的位置设置为1

@Bean
  public Set set() throws IOException {
    Set<String> set = new LinkedHashSet<>();
    FileInputStream inputStream = new FileInputStream(new File("urls.txt"));
    InputStreamReader streamReader = new InputStreamReader(inputStream);
    BufferedReader reader = new BufferedReader(streamReader);
    String line = null;
    while (true) {
      line = reader.readLine();
      if (line != null) {
        set.add(line);
      } else {
        break;
      }
    }
    inputStream.close();
    return set;
  }


  @Bean
  public BloomFilter bloomFilter() throws IOException {
    BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 5000000, 0.01);
    FileInputStream inputStream = new FileInputStream(new File("urls.txt"));
    InputStreamReader streamReader = new InputStreamReader(inputStream);
    BufferedReader reader = new BufferedReader(streamReader);
    String line = null;
    while (true) {
      line = reader.readLine();
      if (line != null) {
        bloomFilter.put(line);
      } else {
        break;
      }
    }
    inputStream.close();
    return bloomFilter;
  }
  
  
@RestController
@RequestMapping("/api")
public class FilterController {
    @Autowired
    private BloomFilter<String> bloomFilter;

    @Autowired
    private Set set;

    @GetMapping("/bloom")
    public String list() throws IOException {

        //判断是否包含这个内容
        if (bloomFilter.mightContain("https://www.dhVrX.com5")) {
            return "命中了";
        } else {
            return "没命中";
        }
    }

    @GetMapping("/set")
    public String set() {
        if (set.contains("httssps://www.shncb.com999663")) {
            return "命中了";
        } else {
            return "没命中";
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/463803.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#求水仙花数

目录 1.何谓水仙花数 2.求三位数的水仙花数 3.在遍历中使用Math.DivRem方法再求水仙花数 1.何谓水仙花数 水仙花数&#xff08;Narcissistic number&#xff09;是指一个 n 位正整数&#xff0c;它的每个位上的数字的 n 次幂之和等于它本身。例如&#xff0c;153 是一个 3 …

数据类型【mysql数据库】

一、数值类型 默认都是有符号&#xff0c;无符号要在对应的类型后跟unsigned 在语言上&#xff0c;可能会有截断&#xff0c;但mysql会对不合法的数据做拦截。所以&#xff0c;mysql中&#xff0c;数据类型本身也是一种约束&#xff08;约束使用者&#xff09;&#xff0c;保证…

后端系统开发之——创建SpringBoot工程

原文地址&#xff1a;后端框架系统开发之——创建SpringBoot工程 - Pleasure的博客 下面是正文内容&#xff1a; 前言 现在的市场环境&#xff0c;如果你单单只是作为前端工程师或者是后端工程师&#xff0c;在开发Web应用的时候都需要去读取企业提供的接口文档。而当你前后端…

编程开发语言工具之透明滑动标尺构件用法

编程开发语言工具之透明滑动标尺构件用法 一、前言 今天给大家分享的编程开发语言工具资料如下&#xff1a; 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载——常用工具下载——编程工具…

数据仓库数据分层详解

数据仓库中的数据分层是一种重要的数据组织方式&#xff0c;其目的是为了在管理数据时能够对数据有一个更加清晰的掌控。以下是数据仓库中的数据分层详解&#xff1a; 原始数据层&#xff08;Raw Data Layer&#xff09;&#xff1a;这是数仓中最底层的层级&#xff0c;用于存…

编译原理-实现识别无符号数的词法分析器——沐雨先生

实验任务&#xff1a; 实现识别无符号数的词法分析器 实验要求&#xff1a; 根据编译原理理论课教材中图2.4“无符号数的转换图”&#xff0c;用C语言编写识别无符号数的词法分析器&#xff0c;以文本文件为输入&#xff0c;控制台&#xff08;或文件&#xff09;输出识别出…

【Sql Server】通过Sql语句批量处理数据,使用变量且遍历数据进行逻辑处理

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

2024Vue高频面试题

前言: Vue 在前端开发领域拥有强劲的发展势头,以下是一些 Vue 的发展趋势: 1.持续增长的用户数量: Vue 作为一款轻量级、易学易用的前端框架,吸引了越来越多的开发者和企业选择使用。其活跃的社区和丰富的资源也促进了用户数量的不断增长。 2.生态系统不断丰富: 随着 V…

第七节:Vben Admin权限-后端获取路由和菜单

系列文章目录 第一节:Vben Admin介绍和初次运行 第二节:Vben Admin 登录逻辑梳理和对接后端准备 第三节:Vben Admin登录对接后端login接口 第四节:Vben Admin登录对接后端getUserInfo接口 第五节:Vben Admin权限-前端控制方式 第六节:Vben Admin权限-后端控制方式 第七节…

【启动npm run serve 奇怪的报错】

报错如下&#xff1a; INFO Starting development server... utils.js:587Uncaught TypeError [ERR_INVALID_ARG_VALUE]: The argument path must be a string or Uint8Array without null bytes. Received E:\\#\u0000#idea-workspace\\wonderful-search\\wonderful-search-v…

【JAVA】JAVA方法的学习和创造

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

影像质感再升级:JOEL FAMULARO Phantom LUTs让作品焕然一新

JOEL FAMULARO Phantom LUTs是一套专业的电影级别的预设&#xff0c;旨在为电影制作人和视频编辑人员提供高质量的颜色校正和调整工具。它为用户提供了一系列精心设计的色彩预设&#xff0c;旨在帮助摄影师在电影、电视和照片后期制作中快速实现专业且一致的色彩风格。这些预设…

自动化测试工具:提升软件质量的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

网络编程套接字——实现简单的UDP网络程序

目录 1、预备知识 1.1、认识端口号 1.2、端口号 vs 进程pid 1.3、认识TCP协议 1.4、认识UDP协议 1.5、网络字节序 2、socket编程接口 2.1、socket常见API 2.2、sockaddr结构 3、实现一个简易的UDP服务器和客户端通信 log.hpp UdpServer.hpp UdpClient.cc Main.cc…

【Maven入门篇】(2)IDEA集成Maven环境的具体操作

&#x1f38a;专栏【Maven入门篇】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The truth that you leave】 &#x1f970;欢迎并且感谢大家指出我的问题 文章目录 &#x1f354;配置Maven环境⭐方法一&#xff08;当前工程&…

EPICS和Arduino Uno之间基于串行文本协议的控制开发

Arduino Uno的串口服务程序设置如文本的串口通信协议设计以及在Arduino上的应用-CSDN博客中所示。通过在串口上发送约定的文本协议&#xff0c;它实现的功能如下&#xff1a; 实现功能&#xff1a; 读取三路0.0V~5.0V模拟量输入&#xff0c;读取端口A0~A2设置三路0.0V~5.0V的模…

光伏电站信息化管理系统如何优化能源管理

随着可再生能源的快速发展&#xff0c;光伏电站作为其中的重要组成部分&#xff0c;其运营管理面临着越来越多的挑战。为了提升光伏电站的能源管理效率&#xff0c;信息化管理系统成为了不可或缺的工具&#xff0c;那么如何优化能源管理呢&#xff1f; 1.数据实时监控 信息化管…

一站式解决方案:uni-app条件编译及多环境配置,appid动态修改攻略!

前言 这篇文章主要介绍uniapp在Hbuilderx 中&#xff0c;通过工程化&#xff0c;区分不同环境、动态修改小程序appid以及自定义条件编译&#xff0c;解决代码发布和运行时手动切换到问题。 背景 在企业级的应用中&#xff0c;通常会分为&#xff0c;开发、联调、生产等多个环…

GPT-1, GPT-2, GPT-3, InstructGPT / ChatGPT and GPT-4 总结

1. GPT-1 What the problem GPT-1 solve? 在 GPT-1 之前&#xff0c;NLP 通常是一种监督模型。 对于每个任务&#xff0c;都有一些标记数据&#xff0c;然后根据这些标记数据开发监督模型。 这种方法存在几个问题&#xff1a;首先&#xff0c;需要标记数据。 但 NLP 不像 CV&…

从嵌套事务的日志看MyBatis的sqlSession生命周期

service层业务代码 Override public void test(){QueryWrapper<StoreRebateCalculateLog> queryWrapper;queryWrapper new QueryWrapper<>();queryWrapper.eq("delete_flag", 0);//执行查询A,A事务开启List<StoreRebateCalculateLog> storeRebat…