大数据判存算法

所谓的大数据判存算法,就是如何在海量数据中快速判断某个数据是否存在。这里用到的知识是布隆过滤器(Bloom Filter),下面按照 what - why - how 的顺序来学习它。

1、什么是布隆过滤器

布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的,布隆过滤器可以用于检索一个元素是否在一个集合中,因此它是一个空间效率极高的概率型算法;它实际上是一个很长的二进制向量和一系列随机映射函数;

上面给出了布隆过滤器的两个核心:二进制向量和一系列随机映射函数。我们说,数据结构的两个必备要素,一是数据,二是算法。二进制向量就是 bit 数据,可以简单的理解为一个只保存 01 的数组;而算法就是这些随机映射函数,可以简单理解成哈希函数。

注意,只保存 01 的数组与哈希函数只是二进制向量和随机映射函数的一种表现形式,不要以偏概全。随机映射函数还有其他形式,只不过布隆过滤器中用到了哈希函数,所以才说可以简单的认为是哈希函数,便于理解这些晦涩的术语。

布隆过滤器(Bloom Filter)是一种空间效率高、适合大规模数据集的概率性数据结构,用于快速检查一个元素是否可能在一个集合中存在。布隆过滤器可以告诉你“可能在集合中”或“肯定不在集合中”,但是不能告诉你“肯定在集合中”。

布隆过滤器的基本原理是使用多个哈希函数以及一个位数组来表示元素的存在情况。当一个元素被加入布隆过滤器时,将这个元素经过多个哈希函数计算出多个哈希值,在位数组对应的位置置为 1。当需要查询元素是否在布隆过滤器中时,同样对元素进行多次哈希计算,检查对应的位数组位置是否都为 1,如果有任何一位不为 1,则可以确定元素一定不在集合中;如果所有位都为 1,则说明元素可能在集合中

下面通过一个业务场景来进一步理解布隆过滤器。假如存在三个物流单号:

2024-08-08.布隆过滤器

想把这些单号存入布隆过滤器中,假设过滤器的映射函数有三个,二进制向量有 24 位。那么每个单号经过 f1、f2、f3 这三个哈希函数运算之后会把向量中的某些位置为 1。当你想要查询某个单号是否在过滤器中时,需要对该单号经过 f1、f2、f3 这三个函数运算,查看计算结果中应该为 1 的位置在向量中是否为 1,如果所有应该为 1 的位置在向量中均为 1,说明该单号可能在向量中,但如果有一位不同,则说明该单号一定不在向量中

布隆过滤器的优点包括:

  1. 空间效率高:相比于传统的数据结构,布隆过滤器可以使用较少的空间来存储大量元素的存在情况。
  2. 查询速度快:布隆过滤器的查询时间复杂度是常数时间 O(n),不受元素数量的影响(受随机映射函数数量 n 的影响,时间复杂度为 O(n))。
  3. 可扩展性强:可以根据需要调整哈希函数的数量和位数组的大小来适应不同规模的数据集。
  4. 信息安全性较高:即便布隆过滤器的数据被盗,由于该数据无法逆向计算,也就无法还原出原本的数据。

然而,布隆过滤器也存在一些缺点,主要包括:

  1. 存在误判:由于多个元素可能映射到同一个位置,因此可能存在误报的情况,即判断元素在集合中,但实际上并不在集合中(哈希碰撞造成的,这种误判率是可以控制的)。
  2. 无法删除元素:一旦元素被加入到布隆过滤器中,就无法从中删除,因为删除一个元素可能会影响其他元素的判断结果(还是由于存在哈希碰撞,可能多个数据的同一个位置都是 1,如果因为删除其中一个数据将该位置为 0 会影响其他数组)。

2、为何学习布隆过滤器

布隆过滤器在实际应用中常被用于缓存、拼写检查、反垃圾邮件过滤等场景,可以有效减少对庞大数据集的访问次数,提高系统性能。

下面列出一些具体的业务场景,主要还是在海量数据之中判断一个元素是否存在:

  • 比如编程 IDE 会提醒你可能拼错的英文单词,画一个红色的下划线。这需要在上百万个单词中去找是否有你写的那个单词
  • 判断身份证号码是否在嫌疑人名单中
  • 360 浏览器提醒你将要访问的网站有潜在危险

3、算法落地

Google Guava 库在 18.0 版本之上提供了布隆过滤器的实现,这里我们看 guava 19.0 版本的源码:

dependencies {implementation 'com.google.guava:guava:19.0'
}

Google Guava 提供了很多基础工具的增强实现,包含了 Google 这些技术天才在进行 Java 开发时凝练出的精华,比 JDK 的功能更强大。比如 Connection、事件总线、哈希算法、IO 增强、反射增强、多线程开发增强、HTML 的解析帮助等等。

3.1 简单使用

我们先来看布隆过滤器一个简单的使用示例:

public class BloomFilterDemo {private static final int insertions = 1_000_000;public void test() {// 创建存储 String 的布隆过滤器,大小为 100WBloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), insertions);HashSet<String> hashSet = new HashSet<>(insertions);ArrayList<String> list = new ArrayList<>(insertions);// 向三个容器初始化 100 万个随机且唯一的字符串,100 万个 uuid 34M 多for (int i = 0; i < insertions; i++) {String uuid = java.util.UUID.randomUUID().toString();bloomFilter.put(uuid);hashSet.add(uuid);list.add(uuid);}// 过滤器判断正确与错误的次数int right = 0, wrong = 0;for (int i = 0; i < 10000; i++) {String test = i % 100 == 0 ? list.get(i / 100) : UUID.randomUUID().toString();if (bloomFilter.mightContain(test)) {if (hashSet.contains(test)) {right++;} else {wrong++;}}}// right = 100 ,wrong = 288System.out.println("right = " + right + " ,wrong = " + wrong);}public static void main(String[] args) {new BloomFilterDemo().test();}
}

对布隆过滤器、HashSet 和 ArrayList 都初始化相同的 100 万个数据。然后从中选择 1 万数据进行测试,先通过 bloomFilter.mightContain() 查看这些数据是否可能在布隆过滤器中,然后对同样的数据再看是否在 HashSet 中。由于 HashSet 的数据不存在误判,因此可以用来衡量 bloomFilter.mightContain() 判断正确和错误的次数,最终输出这些次数,可以看到判断错误的次数是 288。多次运行程序可以发现 right 一直等于 100,而 wrong 一直在 300 左右徘徊,也就是说 10000 个数据中大概有 300 个数据会判断错误,误判率在 3% 左右。

3.2 源码简析

布隆过滤器的实现类是 guava-19.0.jar!\com\google\common\hash\BloomFilter.class,通过查看源码我们发现误判率是可以通过方法参数进行控制的。

我们通过 BloomFilter 的 create() 创建布隆过滤器对象时,可以传不止两个参数:

  public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions) {return create(funnel, (long) expectedInsertions);}public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions}public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp) {return create(funnel, expectedInsertions, fpp, BloomFilterStrategies.MURMUR128_MITZ_64);}

我们在上面的示例中使用的是第一个重载的 create(),指定了 Funnel 接口的具体类型为 StringCharsetFunnel,还指定了插入数据的数量 expectedInsertions 为 100 万。该方法会调用三个参数的 create(),增加的参数 fpp 就是误判率,默认指定为 0.03 也就是 3%,与上面例子中的数据吻合。

也就是说,误判率可以通过方法的参数显示指定。

然后我们先看 create() 最终会被调用的、拥有 4 个参数的重载方法:

  @VisibleForTestingstatic <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy) {checkNotNull(funnel);checkArgument(expectedInsertions >= 0, "Expected insertions (%s) must be >= 0", expectedInsertions);checkArgument(fpp > 0.0, "False positive probability (%s) must be > 0.0", fpp);checkArgument(fpp < 1.0, "False positive probability (%s) must be < 1.0", fpp);checkNotNull(strategy);if (expectedInsertions == 0) {expectedInsertions = 1;}// numBits 是二进制向量的长度,numHashFunctions 是随机映射函数,也就是哈希函数的个数long numBits = optimalNumOfBits(expectedInsertions, fpp);int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);try {return new BloomFilter<T>(new BitArray(numBits), numHashFunctions, funnel, strategy);} catch (IllegalArgumentException e) {throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", e);}}

运行程序打断点,在误判率为默认的 3% 的情况下,numBits = 7298440,numHashFunctions = 5。但是如果调用 create() 创建过滤器时将误判率设置为 0.1% 的话:

BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), insertions, 0.001);

再次进行断点调试,会发现 numBits = 14377587,numHashFunctions = 10。说明想要降低误判率,是需要复出增多二进制向量位数和哈希函数数量的代价的。至于为什么是这些数量,是 Google 工程师根据大量测算给出的推荐值。

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

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

相关文章

Solr-搜索引擎-入门到精通

以下是对 Apache Solr 的简介及其常用语法的快速入门指南&#xff1a; 一、Solr 是什么&#xff1f; • 核心定位&#xff1a;Apache Solr 是一个基于 Lucene 的高性能、开源的搜索平台&#xff0c;支持全文检索、分词、高亮、聚合统计等功能。 • 核心功能&#xff1a; • 全…

Ajax与Axios,以及Apifox的入门使用

Ajax与Axios&#xff0c;以及Apifox的入门使用 作者&#xff1a;blue 时间&#xff1a;2025.3.20 文章目录 Ajax与Axios&#xff0c;以及Apifox的入门使用1.Ajax2.Axios3.Apifox的基本使用内容Path 参数定义语法用途 Query 参数定义语法用途 1.Ajax 概念&#xff1a;Asynchr…

Spring MVC拦截器

一、什么是拦截器 拦截器是 SpringMVC 提供的一种可以在请求处理过程中对请求进行预处理或后处理的机制。简单来说&#xff0c;拦截器就像是一位“守门员”&#xff0c;它拦住所有进来的请求&#xff0c;根据设定的规则决定是否放行或者进行某些操作。 拦截器可以&#xff1a…

mysql语句 聚合+分组+内外链接

1.聚合函数 1.count 记数 2.sum 求和 3.avg *语法&#xff1a;select avg&#xff08;列名&#xff09; from 表名&#xff1b; 4.max 求最大值 5.min 求最小值 求一个班级数学平均分&#xff1f; select avg&#xff08;ifnull&#xff08;math&#xff0c;0&#x…

WPF 与 C# 融合开发:从基础到高级应用(一)

WPF 与 C# 融合开发&#xff1a;从基础到高级应用 一、C# 语言基础回顾 1.1 C# 语言概述 C# 是微软开发的一种现代、面向对象的编程语言&#xff0c;它融合了 C、C 和 Java 等语言的优点&#xff0c;具有简洁、安全、高效等特点。C# 广泛应用于 Windows 平台的应用开发&…

【Linux】IP协议

目录 一、IP协议的概念 二、IP协议的报头 &#xff08;一&#xff09;IP协议报文的封装、解包和分用 &#xff08;二&#xff09;8位生存时间 &#xff08;三&#xff09;IP分片 三、IP协议的网段划分 &#xff08;一&#xff09;为什么需要网段划分 &#xff08;二&am…

如何快速下载并安装 Postman?

从下载、安装、启动 Postman 这三个方面为大家详细讲解下载安装 Postman 每一步操作&#xff0c;帮助初学者快速上手。 Postman 下载及安装教程(2025最新)

计算机网络高频(三)UDP基础

计算机网络高频(三)UDP基础 1.UDP的头部格式是什么样的?⭐ UDP 头部具有以下字段: 源端口(Source Port):16 位字段,表示发送方的端口号。目标端口(Destination Port):16 位字段,表示接收方的端口号。长度(Length):16 位字段,表示 UDP 数据报(包括头部和数据部…

2024年MathorCup数学建模B题甲骨文智能识别中原始拓片单字自动分割与识别研究解题全过程文档加程序

2024年第十四届MathorCup高校数学建模挑战赛 B题 甲骨文智能识别中原始拓片单字自动分割与识别研究 原题再现&#xff1a; 甲骨文是我国目前已知的最早成熟的文字系统&#xff0c;它是一种刻在龟甲或兽骨上的古老文字。甲骨文具有极其重要的研究价值&#xff0c;不仅对中国文…

【深度学习的数学】导数

导数的定义。好像是从极限开始的。比如说&#xff0c;函数f(x)在点xa处的导数&#xff0c;就是当h趋近于0时&#xff0c;[f(ah) - f(a)]除以h的极限&#xff0c;对吧&#xff1f;公式应该是这样的&#xff1a;f’(a) lim_{h→0} [f(ah) - f(a)] / h。这个极限如果存在的话&…

word文件转换为Markdown格式

目录 一、前言1.1、poi-ooxml、docx4j、aspose-words对比二、poi-ooxml技术实现一、前言 顺应时代技术的变更及高效协同理念的影响,非结构化信息展示、存储、应用等也由传统文档向在线协同文档的演变,类似腾讯在线文档。   目前大多数在线文档支持的是Markdown格式,因此这…

【Hugging Face 开源库】Diffusers 库 —— 扩散模型

Diffusers 的三个主要组件1. DiffusionPipeline&#xff1a;端到端推理工具__call__ 函数callback_on_step_end 管道回调函数 2. 预训练模型架构和模块UNetVAE&#xff08;Variational AutoEncoder&#xff09;图像尺寸与 UNet 和 VAE 的关系EMA&#xff08;Exponential Moving…

langserve搭建方法

文章目录 安装 langserver安装 langchain-cli创建langserve脚手架使用poetry管理包 安装 langserver pip install langserve安装 langchain-cli pip install langchain-cli创建langserve脚手架 langchain app new 项目名后续交互界面全回车&#xff0c;接着cd到 项目名 目录…

网络基础-路由器和交换机工作配置

三、路由器和交换机的工作原理配置以及华为体系下的小型网络的搭建 3.1路由基础 3.1.1数据转发 通过链路层交换机和网络层路由器进行数据转发 交换机&#xff08;链路层&#xff09;mac地址表的数据转发路由器&#xff08;网络层&#xff09; ip路由表的数据转发 隔离广播域…

mysql高级,mysql体系结构,mysql引擎,存储过程,索引,锁

1.mysql体系结构 1&#xff09; 连接层 主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念&#xff0c;为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作…

Unity高清渲染管线

Unity高清渲染管线——1 unity高清渲染管线是渲染管线的一种&#xff0c;在看完《创造高清3D虚拟世界》这本书的前两章以及第三张第二小节后终于对unity的高清渲染管线也是有了一个初步的认知&#xff0c;以下是我个人理解仅作参考&#xff1a; unity高清渲染管线项目模板比起…

Python基础语法元素(学习笔记)

实例1&#xff1a;温度转换 # TempConvert.py #为单行注释 多行注释为: 这里写内容 TempStr input("请输入带有符号的温度值&#xff1a;") if TempStr[-1] in [F,f] :C (eval(TempStr[0:-1])-32)/1.8print("转换后的温度是{:.2f}C".format(C)) e…

C++20 中的std::c8rtomb和 std::mbrtoc8

文章目录 1. 引言2. std::c8rtomb 函数详解3. std::mbrtoc8 函数详解4. 使用示例5. 注意事项6. 总结 1. 引言 C20 标准引入了对 UTF-8 编码的更好支持&#xff0c;其中包括两个重要的函数&#xff1a;std::c8rtomb 和 std::mbrtoc8。这两个函数分别用于将 UTF-8 编码的字符转换…

数据可视化TensorboardX和tensorBoard安装及使用

tensorBoard 和TensorboardX 安装及使用指南 tensorBoard 和 TensorBoardX 是用于可视化机器学习实验和模型训练过程的工具。TensorBoard 是 TensorFlow 官方提供的可视化工具&#xff0c;而 TensorBoardX 是其社区驱动的替代品&#xff0c;支持 PyTorch 等其他框架。以下是它…

flutter-实现瀑布流布局及下拉刷新上拉加载更多

文章目录 1. 效果预览2. 结构分析3. 完整代码4. 总结 1. 效果预览 在 Flutter 应用开发中&#xff0c;瀑布流布局常用于展示图片、商品列表等需要以不规则但整齐排列的内容。同时&#xff0c;下拉刷新和上拉加载更多功能&#xff0c;能够极大提升用户体验&#xff0c;让用户方…