位图布隆过滤器

文章目录

  • 位图&布隆过滤器
    • 1. 位图
      • 1.1位图概念
      • 1.2位图原理
      • 1.3位图实现
      • 1.4位图排序
    • 2. 布隆过滤器
      • 2.1 引入布隆过滤器
      • 2.2 概念
      • 2.3 布隆过滤器插入
      • 2.4 布隆过滤器的查找
      • 2.5 布隆过滤器模拟实现
      • 2.6 布隆过滤器的删除
      • 2.7 布隆过滤器优缺点
      • 2.8 布隆过滤器使用场景
    • 3. 海量数据问题


位图&布隆过滤器

1. 位图

给定40亿个不重复的正整数,如何快速判断一个数组是否在这40亿个数中。解决方案:

  1. 直接遍历,时间复杂度 O ( n ) O(n) O(n)
  2. 排序后二分查找,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

以上方法使能解决,但如果考虑到空间复杂度40亿个正整数需要将近15G的内存,如果内存不存就无法做到。那么此时就可以引入位图。

1.1位图概念

位图是一种数据结构,它通过每一个比特位来存放某一种状态,适合存储海量的数据,整数,数据无重复的场景,一般是用来判断某一个数据是否存在的。

比如上面那个例子,一个整数就是4个字节, 4 ∗ 4000000000 / 1024 / 1024 / 1024 4*4000000000/1024/1024/1024 44000000000/1024/1024/1024,大约是占用了15G的内存,而如果使用位图存储这40亿个正整数, 4000000000 / 32 ∗ 4 / 1024 / 1024 4000000000/32*4/1024/1024 4000000000/324/1024/1024,大约就是480M的内存。这个内存占用直接降低了一个数量级。

1.2位图原理

一个数据是否存也就两种状态,在或者不在,通过二进制的0和1就可以表示,位图存储数据就是通过比特位来判断数据是否在位图中存在,0表示不存在1表示存在。通过公式计算出一个数据在哪个比特位。下图分别表示3个数组下标,每个下标都是1个字节(Byte)。

  • 计算数组下标公式:数值/8​
  • 计算算在数数据在某个下标某一个比特位上:数值%8​
  • 加设要把3存入位图,3/8得到数组下标为03%8得到比特位为3,所以元素3要存放到下标为0位置的第3个比特位处。

在这里插入图片描述

1.3位图实现

位图实现主要的3个功能:

  • 设置元素到位图中,通过按位与运算给对应比特位设置为1,假设存14到位图中

    在这里插入图片描述

  • 查询一个元素是否在位图中,以同样的方法进行按位与运算判断对应位置是否为1,如图下标为1的位置的第6个比特位是否为1

    在这里插入图片描述

  • 把一个元素从位图中移除,通过按位取反再进行按位与运算来移除对应标注的二进制位,假设要移除的是19

    在这里插入图片描述

import java.util.Arrays;public class MyBitSet {private byte[] elem;public MyBitSet() {this.elem = new byte[8];}public MyBitSet(int nBits) {this.elem = new byte[nBits];}/*** 添加 bitIndex元素到位图中* @param bitIndex*/public void set(int bitIndex) {if (bitIndex < 0) {throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);}// 计算数组下标int index = bitIndex/8;if (index >= elem.length) {// 扩容elem = Arrays.copyOf(elem,index+1);}// 计算二进制位int bit = bitIndex%8;elem[index] |= (1<<bit);}/*** 判断 bitIndex元素在位图中是否存在* @param bitIndex* @return*/public boolean get(int bitIndex) {if (bitIndex < 0) {throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);}// 计算数组下标int index = bitIndex/8;if (index >= elem.length) {return false;}// 计算二进制位int bit = bitIndex%8;if ((elem[index]&(1<<bit)) != 0) {return true;}return false;}public void remove(int bitIndex) {if (bitIndex < 0) {throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);}// 计算数组下标int index = bitIndex/8;if (index >= elem.length) {return;}// 计算二进制位int bit = bitIndex%8;elem[index] &= (~(1<<bit));}
}

1.4位图排序

可以利用位图来进行简单的排序,也就是从第一个比特位开始判断是否有元素,有元素以存入的方式进行取出。

public void sort(int[] elem) {for (int i = 0; i < elem.length; i++) {for (int j = 0; j < 8; j++) {if (((elem[i]>>>j)&1) == 1) {System.out.print(j+(i*8)+" ");}}}
}

2. 布隆过滤器

2.1 引入布隆过滤器

在编程时,我们经常要判断一个元素是否在一个集合中出现,第一时间想到的应该是哈希表,它的优点就是增删改查快速又准确,缺点也是有的那就是存在着空间的浪费,当数据量非常大时就凸显出来了,数据量非常大时哈希表会存在非常多的key,同时发送大量的哈希冲突,使用链地址方法来解决,从而产生大量的节点占用大量的空间,如果使用线性探测就会降低查询效率。假设要判断一个email是否在几十亿的email中出现。

如果用哈希表存储一亿个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个
email 地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有
50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要 1.6GB, 即十六亿字节的内存)。因此
存贮几十亿个邮件地址可能需要上百 GB 的内存。

方法:

  1. 是哈希表存储用户记录,缺点:占用大量空间
  2. 使用用位图存储用户记录?无法实现,因为位图只能处理整形。
  3. 将哈希和位图进行结合,也就是布隆过滤器

2.2 概念

布隆过滤器是一种比较巧妙的概率形数据结果,其特点是高效地插入和查询,可以用来告诉你“某样东西一定不存在或者可能存在”,布隆过滤器使用多个哈希函数,将一个数据映射到位图结构中。从而提升查询效率,也可以节省大量的内存空间。

在这里插入图片描述

2.3 布隆过滤器插入

假设布隆过滤器中有3个hash函数,要往布隆过滤器中插入"hello world",通过3个不同的hash函数得到不同的hash值,然后再把hash值设置在位图的3个比特位中。

在这里插入图片描述

2.4 布隆过滤器的查找

布隆过滤器的基本思想是将一个元素通过多个hash函数得到hash值后,设置到位图的不同比特位中。查询通过同样的hash函数去判断位图对应的比特位是否为1,只要一个比特位不唯一,那么这个元素就一定不存在,相反查询的比特位全部唯一也只是可能存在。因为通过hash函数必定会发生hash冲突,可能会出现下图这种情况:

"hello java"和"hello world"两个元素已经存放到布隆过滤器中,此时"test code"未存放到布隆过滤器中,此时去查询"test code"中查询的时候恰巧hash到的位图中的位置,都被"hello"和“hello world“标记过了,此时就返回"test code"这个元素存在吗?显然是不存在的。所以布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判

在这里插入图片描述

2.5 布隆过滤器模拟实现

通过参考HashMap的哈希函数再随缘加上一些随机因子,使用了3个哈希函数对元素进行哈希并设置到位图当中。

/*** 布隆过滤器模拟实现* @param <E>*/
public class BloomFilter<E> {static class RandomHash {// 容量int size;// 随机种子int seed;public RandomHash(int size, int seed) {this.size = size;this.seed = seed;}/*** 计算机哈希值* @param key 元素* @return*/private int hash(Object key) {int h;// (n-1)&hash == hash%nreturn (key == null) ? 0 : (seed*(size-1))&(h = key.hashCode()) ^ (h >>> 16);}}// 位图默认容量,参照hashmap,方便hash函数计算private static final int DEFAULT_SIZE = 1 << 21;// 随机因子private static final int[] RANDOM_FACTOR = {3,7,11};// 布隆过滤器元素个数private int size;private BitSet bitSet;// 哈希函数private RandomHash[] randomHashes;public BloomFilter() {bitSet = new BitSet(DEFAULT_SIZE);randomHashes = new RandomHash[RANDOM_FACTOR.length];for (int i = 0; i < randomHashes.length; i++) {randomHashes[i] = new RandomHash(DEFAULT_SIZE,RANDOM_FACTOR[i]);}}/*** 添加元素到布隆过滤器中* @param key*/public void add(E key) {for (int i = 0; i < randomHashes.length; i++) {int hash = randomHashes[i].hash(key);bitSet.set(hash);}}/*** 判断元素是否可能存在布隆过滤中* @param key* @return*/public boolean contains(E key) {for (int i = 0; i < randomHashes.length; i++) {int hash = randomHashes[i].hash(key);if (!bitSet.get(hash)) {return false;}}return true;}public static void main(String[] args) {BloomFilter<Integer> bloomFilter = new BloomFilter<>();for (int i = 1000; i < 2000; i++) {bloomFilter.add(i);}int count = 0;for (int i = 1000; i <= 70000000; i++) {if (bloomFilter.contains(i)) {count++;}}System.out.println(count);}
}

2.6 布隆过滤器的删除

布隆过滤器是无法直接删除的,和查询类似会存在误删除。因为存储元素必定会存在哈希冲突的,如果删除一个元素则会把对应的比特位标记为0,一旦有其它元素也哈希到了这个位置,那么也会就会影响到其它元素,因为布隆过滤器查询的时候只要有一个比特位为0,就认为这个元素一定不存在。所以布隆过滤器不能直接删除。

如果想实现布隆过滤器的删除:可以采用加减标记的方式,一起添加元素是将hash过后的比特位标记成1,可以改成给位图对应的位置+1,删除就给对应的位图下标-1,但这样做需要更大的空间,而且+1和-1存溢出问题。

2.7 布隆过滤器优缺点

优点:

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关

  2. 哈希函数相互之间没有关系,方便硬件并行运算

  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势

  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势

  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能

  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

缺点:

  1. 无法确认元素是否真正在布隆过滤器中,误判问题
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题

2.8 布隆过滤器使用场景

  1. 网络爬虫:在网络爬取数据的过程中,可以使用布隆过滤器来过滤掉已经爬取过的网页链接,避免重复爬取相同的内容。
  2. 缓存服务:在缓存中使用布隆过滤器可以快速判断某个数据是否存在于缓存中,如果不存在就从数据库或其他存储中获取,并将其添加到缓存中,减轻数据库或存储系统的负载压力。
  3. 反垃圾邮件系统:布隆过滤器可以用于过滤垃圾邮件。将已知的垃圾邮件发送者的信息加入到布隆过滤器中,当新邮件到达时,可以快速判断其发件人是否为已知的垃圾邮件发送者,从而减少用户收到垃圾邮件的数量。
  4. 分布式系统:在分布式系统中,布隆过滤器可以用于去重操作,避免重复处理相同的数据和请求。各个节点可以共享一个布隆过滤器,快速判断某个数据是否已经被处理过。

总的来说,布隆过滤器适用于需要快速判断某个元素是否存在的场景,并且能够容忍一定的错误率

3. 海量数据问题

问题1

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?

该问题可以使用哈希切割,新建200个文件,每个文件存储500M的数据,从文件中开始读取100G的数据,对读取到的ip地址进行哈希后,再对hash值%200存放到对应的文件中。最后依次读取200个文件,记录ip出现的次数即可。同理,如果是TOP k问题,也是如此。

在这里插入图片描述

3.2 问题2

给定100亿个整数,设计算法找到只出现一次的整数? 100亿个整数大概是 10000000000 ∗ 4 / 1024 / 1024 / 1024 10000000000*4/1024/1024/1024 100000000004/1024/1024/1024,40G的大小,显然内存是存不下的。

解法1:

同理可以使用Hash切割,将这100亿个数hash到不同文件上,再遍历文件即可。

解法2:

100亿个整数存放到一个位图大概是 10000000000 / 32 ∗ 4 / 1024 / 1024 / 1024 10000000000/32*4/1024/1024/1024 10000000000/324/1024/1024/1024,大概就是1个G的内存。

使用两个位图,可以表示数组出现了多少次,1次、2次或者3次。

比如说:

  • 位图1的第0个比特位为0位图2第0个比特位为1,就表示对应位置的数出现的次数为1
  • 位图1的第0个比特位为1位图2第0个比特位为0,就表示对应位置的数出现的次数为2
  • 位图1的第0个比特位为1位图2第0个比特位为1,就表示对应位置的数出现了3次

在这里插入图片描述

解法3:使用一个位图

和解法2类似,采用类似二进制的表示出现的次数,只不过使用一个位图要两个比特位才能表示一个数字。

原本的公式是:下标: i n d e x = k e y / 8 index = key/8 index=key/8,比特位: b i t = k e y bit = key bit=key% 8 8 8

采用两个比特位标识一个数字:下标 i n d e x = k e y / 4 index = key/4 index=key/4,比特位: b i t = k e y bit = key bit=key% 4 ∗ 2 4*2 42

在这里插入图片描述

问题3

给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

解法1:

使用hash切割,把两个文件先分别分割成200个文件,也就是400个文件,读取文件1分割的问题件的同时去读取文件2对应分割的文件,由于hash函数是一致的,相同的数字会被放到同一个文件中,比如说文件1分割出来的文件1.1和文件2分割出来的2.1,使用的是同一个哈希函数,只要在两个文件里找相同的数字即可。

解法2:

使用位图把第一个文件中的数据存到位图中,再遍历第二个文件中的数字看看是否在位图中存在,存在就是交集。

问题4

1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

解法1:

hash切割,切割到多个文件,一个一个文件统计

解法2:

使用两个位图,只要两个位图没有同时为1,那就是没有超过两次

问题5

给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和
近似算法

精确算法:两个文件分别哈希切割成多个文件,分两组。在依次对应读取两个文件判断是否有相同的存在。

近似算法:把一个文件的数据读取到布隆过滤器,再读取第二个问题,判断是否存在,显然会存在误判。


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浙江移动与中兴通讯合作项目被评为“光华杯”东部赛区一等奖!

近日&#xff0c;浙江移动携手中兴通讯共同打造的创新合作项目“构建面向东数西算的传输全光底座赋能美丽浙江”在2023年第二届“光华杯”东部赛区决赛中被评为一等奖&#xff0c;该项目以运力为核心&#xff0c;可实践应用于“东数西算”建设工程当中&#xff0c;提供高速无阻…

interview6-jvm篇

JVM(Java Virtual Machine)Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 在JVM中共有四大部分&#xff0c;分别是ClassLoader&#xff08;类加载器&#xff09;、Runtime DataArea&#xff08;运行时数据区&#xff0c;内存分区&#xff09;、Execu…

探索创意的新辅助,AI与作家的完美合作

在现代社会&#xff0c;文学创作一直是人类精神活动中的重要一环。从古典文学到现代小说&#xff0c;从诗歌到戏剧&#xff0c;作家们以他们的独特视角和文学天赋为我们展示了丰富多彩的人生世界。而近年来&#xff0c;人工智能技术的快速发展已经渗透到各行各业&#xff0c;文…

JavaWeb 学习

1. 基本概念 1.1 Web web&#xff1a;网络&#xff0c;网页 静态 web html&#xff0c;css提供给所有人看的数据始终不会变化 动态 web 淘宝提供给每个人看的数据会有所不同技术栈&#xff1a;Servlet/JSP&#xff0c;ASP&#xff0c;PHP Java 中&#xff0c;动态 web 资…

【神印王座】悲啸洞穴之物揭晓,圣采儿差点被骗,幸好龙皓晨聪明

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析神印王座。 神印王座动漫现阶段已经出到龙皓晨等人接取新任务深入魔族地界的阶段&#xff0c;而龙皓晨等人接取的任务想必现在大家都知道了&#xff0c;那就是探索魔族地界中的悲啸洞穴。但是大家知道悲啸洞穴里面藏着什么…

缓冲区溢出漏洞分析

一、实验目的 熟悉软件安全需求分析方法&#xff0c;掌握软件安全分析技术。 二、实验软硬件要求 1、操作系统&#xff1a;windows 7/8/10等 2、开发环境&#xff1a;VS 6.0&#xff08;C&#xff09;、OllyDbg 三、实验预习 《软件安全技术》教材第3章 四、实验内容&#…

CSS滚动条详解(::-webkit-scrollbar )

滚动条出现的事件&#xff1a; 当设置定宽或者定高的元素添加overflow:scroll属性&#xff0c;会出现滚动条&#xff0c;但是原生样式的会比较丑影响美观。 <div class"content"><div class"contain"></div> </div>.content {wid…

CleanMyMac X版本4.14.2中文版新功能介绍

CleanMyMac X版本4.14.2中文版是一款专业的Mac清理工具&#xff0c;只需要一键智能清理&#xff0c;便能让Mac恢复原始的性能&#xff0c;是MAC系统非常好用的工具。CleanMyMac X自身拥有一个安全数据库&#xff0c;它是一个项目列表&#xff0c;拥有一定的规格&#xff0c;可以…

数据结构与算法(C语言版)P6---队列

1、队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除操作的特殊线性表&#xff0c;队列具有__先进先出__FIFO&#xff08;First In First Out&#xff09; 入队列&#xff1a;进行插入操作的一端称为__队尾__。 出队列&#xff1a;…

Cpp/Qt-day040920Qt

目录 时钟 头文件&#xff1a;Widget.h: 源文件:Widget.c: 效果图&#xff1a; 思维导图 时钟 头文件&#xff1a;Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QPainter> #include <QTime>…

性能测试 —— 性能测试常见的测试指标 !

一、什么是性能测试 先看下百度百科对它的定义&#xff0c;性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。 我们可以认为性能测试是&#xff1a;通过在测试环境下对系统或构件的性能进行探测&#xff0c;用以验证在生产环…

安防视频/集中云存储平台EasyCVR(V3.3)部分通道显示离线该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

it运维监控主要做什么

IT运维监控已成为企业经营的重要组成部分。为了保证全面高效的运行&#xff0c;提升企业的经营效率和服务水平&#xff0c;主要从事对企业的IT基础设施进行监控和管理。所以&#xff0c;IT运维监控的关键是什么&#xff1f; IT运维监控的主要任务是确保IT基础设施的正常使用。它…

Gitee使用用户名密码登录一直错误/IDEA连接gitee仓库密码错误

天坑,注册的时候名字带了大写,用户名自动给你变成小写 真正的用户名在个人主页里面看,是后面的字符,才是真正的用户名.排查了一个小时密码问题,真的坑

百度SEO优化不稳定的原因分析(提升网站排名的稳定性)

百度SEO优化不稳定介绍蘑菇号-www.mooogu.cn SEO不稳定是指网站在搜索引擎中的排名不稳定&#xff0c;随着时间的推移会发生变化。这种情况可能会出现在网站页面结构、内容质量、外链质量等方面存在缺陷或不合理之处。因此&#xff0c;优化SEO非常重要&#xff0c;可以提高网站…

Gateway网关

网关GateWay 官方文档&#xff1a;https://docs.spring.io/spring-cloud-gateway/docs/3.1.2/reference/html/#gateway-how-it-works 核心概念 路由: 网关的核心数据结构&#xff0c;定义了网关如何处理请求. 一条路由信息包含路由的唯一标识ID,目的地URI, 一组断言&#xf…

融云 CallPlus + X,通话场景一站式解决方案

融云近期上线的 CallPlus SDK&#xff0c;针对音视频呼叫场景单独设计后端服务 Call Server&#xff0c;信令延时低至 150ms&#xff0c;确保各端计时准确、一致&#xff1b;上线了音视频通话互转、灵活的多人通话、通话记录管理能力等功能。关注【融云全球互联网通信云】了解更…

regsvr32 initpki.dll找不到指定模块要怎么解决?教你快速修复initpki.dll文件

当你尝试在 Windows 操作系统中注册 DLL 文件时&#xff0c;可能会遇到错误消息&#xff1a;“regsvr32 initpki.dll找不到指定模块”。它通常是由于一个或多个 DLL 文件缺失或损坏所导致的。这是一个常见的错误&#xff0c;并且可以遇到在 Windows 7、Windows 8 和 Windows 10…

点餐小程序的制作流程详解

随着移动互联网的发展&#xff0c;越来越多的消费者开始使用手机进行点餐&#xff0c;这也促使了点餐小程序的兴起。如果您是一位商家&#xff0c;想要开发一个属于自己的点餐小程序&#xff0c;那么不妨尝试一下以下的DIY教程吧&#xff01; 首先&#xff0c;我们需要找一个专…

Android存储权限完美适配(Android11及以上适配)

一、Bug简述 一个很普通的需求&#xff0c;需要下载图片到本地&#xff0c;我的三个测试机&#xff08;荣耀Android10&#xff0c;红米 11 和小米Android 13都没有问题&#xff09;。 然后&#xff0c;主角登场了&#xff0c;测试的三星Android 13 死活拉不起存储权限弹窗。 …