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


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

    基本介绍

            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地址都处理完毕,完成去重。

    1. POM 依赖
    2. <dependencies>
    3. <dependency>
    4. <groupId>org.springframework.bootgroupId>
    5. <artifactId>spring-boot-starter-webartifactId>
    6. dependency>
    7. <dependency>
    8. <groupId>org.springframework.bootgroupId>
    9. <artifactId>spring-boot-starter-testartifactId>
    10. <scope>testscope>
    11. dependency>
    12. <dependency>
    13. <groupId>org.apache.commonsgroupId>
    14. <artifactId>commons-lang3artifactId>
    15. <version>3.12.0version>
    16. dependency>
    17. <dependency>
    18. <groupId>com.google.guavagroupId>
    19. <artifactId>guavaartifactId>
    20. <version>31.1-jreversion>
    21. dependency>
    22. dependencies>
    1. @Test
    2. public void testGeneUrl() {
    3. try{
    4. File file = new File("urls.txt");
    5. if (!file.exists()) {
    6. file.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖
    7. }
    8. FileOutputStream fos = new FileOutputStream(file, true);
    9. OutputStreamWriter osw = new OutputStreamWriter(fos);
    10. BufferedWriter bw = new BufferedWriter(osw);
    11. StringBuilder builder = new StringBuilder();
    12. for (int i = 0; i < 5000000; i++) {
    13. String name = RandomStringUtils.randomAlphabetic(5);
    14. String fileName = "https://www." + name + ".com" + i + "\n";
    15. builder.append(fileName);
    16. }
    17. bw.write(String.valueOf(builder));
    18. bw.newLine();
    19. bw.flush();
    20. bw.close();
    21. osw.close();
    22. fos.close();
    23. } catch (FileNotFoundException e1) {
    24. e1.printStackTrace();
    25. } catch (IOException e2) {
    26. e2.printStackTrace();
    27. }
    28. }

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

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

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

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

    1. @Bean
    2. public Set set() throws IOException {
    3. Set set = new LinkedHashSet<>();
    4. FileInputStream inputStream = new FileInputStream(new File("urls.txt"));
    5. InputStreamReader streamReader = new InputStreamReader(inputStream);
    6. BufferedReader reader = new BufferedReader(streamReader);
    7. String line = null;
    8. while (true) {
    9. line = reader.readLine();
    10. if (line != null) {
    11. set.add(line);
    12. } else {
    13. break;
    14. }
    15. }
    16. inputStream.close();
    17. return set;
    18. }
    19. @Bean
    20. public BloomFilter bloomFilter() throws IOException {
    21. BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 5000000, 0.01);
    22. FileInputStream inputStream = new FileInputStream(new File("urls.txt"));
    23. InputStreamReader streamReader = new InputStreamReader(inputStream);
    24. BufferedReader reader = new BufferedReader(streamReader);
    25. String line = null;
    26. while (true) {
    27. line = reader.readLine();
    28. if (line != null) {
    29. bloomFilter.put(line);
    30. } else {
    31. break;
    32. }
    33. }
    34. inputStream.close();
    35. return bloomFilter;
    36. }
    37. @RestController
    38. @RequestMapping("/api")
    39. public class FilterController {
    40. @Autowired
    41. private BloomFilter bloomFilter;
    42. @Autowired
    43. private Set set;
    44. @GetMapping("/bloom")
    45. public String list() throws IOException {
    46. //判断是否包含这个内容
    47. if (bloomFilter.mightContain("https://www.dhVrX.com5")) {
    48. return "命中了";
    49. } else {
    50. return "没命中";
    51. }
    52. }
    53. @GetMapping("/set")
    54. public String set() {
    55. if (set.contains("httssps://www.shncb.com999663")) {
    56. return "命中了";
    57. } else {
    58. return "没命中";
    59. }
    60. }
    61. }

  • 相关阅读:
    上周热点回顾(6.10-6.16)
    网络基础—网关、网段、子网掩码
    GAN 生成对抗神经网络
    九、Linux用户管理
    分类分析模型
    虚幻引擎:C++网络属性同步
    Unity --- 脚本组件 --- 生命周期与执行顺序
    WorkManager学习一
    YOLOv5论文作图教程(2)— 软件界面布局和基础功能介绍
    菊风视频能力平台通过浙江省信创适配实验室验证测试
  • 原文地址:https://blog.csdn.net/qq_30294911/article/details/136758990