当前位置: 首页 > news >正文

Redis 中的布隆过滤器

原文链接: https://jaychen.cc/redis/2018...
作者:JayChen

什么是『布隆过滤器』

布隆过滤器是一个神奇的数据结构,可以用来判断一个元素是否在一个集合中。很常用的一个功能是用来去重。在爬虫中常见的一个需求:目标网站 URL 千千万,怎么判断某个 URL 爬虫是否宠幸过?简单点可以爬虫每采集过一个 URL,就把这个 URL 存入数据库中,每次一个新的 URL 过来就到数据库查询下是否访问过。

select id from table where url = 'https://jaychen.cc'

但是随着爬虫爬过的 URL 越来越多,每次请求前都要访问数据库一次,并且对于这种字符串的 SQL 查询效率并不高。除了数据库之外,使用 Redis 的 set 结构也可以满足这个需求,并且性能优于数据库。但是 Redis 也存在一个问题:耗费过多的内存。这个时候布隆过滤器就很横的出场了:这个问题让我来。

相比于数据库和 Redis,使用布隆过滤器可以很好的避免性能和内存占用的问题。

布隆过滤器本质是一个位数组,位数组就是数组的每个元素都只占用 1 bit 。每个元素只能是 0 或者 1。这样申请一个 10000 个元素的位数组只占用 10000 / 8 = 1250 B 的空间。布隆过滤器除了一个位数组,还有 K 个哈希函数。当一个元素加入布隆过滤器中的时候,会进行如下操作:

  • 使用 K 个哈希函数对元素值进行 K 次计算,得到 K 个哈希值。
  • 根据得到的哈希值,在位数组中把对应下标的值置为 1。

举个?,假设布隆过滤器有 3 个哈希函数:f1, f2, f3 和一个位数组 arr。现在要把 https://jaychen.cc 插入布隆过滤器中:

  • 对值进行三次哈希计算,得到三个值 n1, n2, n3。
  • 把位数组中三个元素 arr[n1], arr[n2], arr[3] 置为 1。

当要判断一个值是否在布隆过滤器中,对元素再次进行哈希计算,得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值在布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

看不懂文字看下面的灵魂画手的图解释???

看了上面的说明,必然会提出一个问题:当插入的元素原来越多,位数组中被置为 1 的位置就越多,当一个不在布隆过滤器中的元素,经过哈希计算之后,得到的值在位数组中查询,有可能这些位置也都被置为 1。这样一个不存在布隆过滤器中的也有可能被误判成在布隆过滤器中。但是如果布隆过滤器判断说一个元素不在布隆过滤器中,那么这个值就一定不在布隆过滤器中。简单来说:

  • 布隆过滤器说某个元素在,可能会被误判。
  • 布隆过滤器说某个元素不在,那么一定不在。

这个布隆过滤器的缺陷放到上面爬虫的需求中,可能存在某些没有访问过的 URL 可能会被误判为访问过,但是如果是访问过的 URL 一定不会被误判为没访问过。

Redis 中的布隆过滤器

redis 在 4.0 的版本中加入了 module 功能,布隆过滤器可以通过 module 的形式添加到 redis 中,所以使用 redis 4.0 以上的版本可以通过加载 module 来使用 redis 中的布隆过滤器。但是这不是最简单的方式,使用 docker 可以直接在 redis 中体验布隆过滤器。

> docker run -d -p 6379:6379 --name bloomfilter redislabs/rebloom
> docker exec -it bloomfilter redis-cli

redis 布隆过滤器主要就两个命令:

  • bf.add 添加元素到布隆过滤器中:bf.add urls https://jaychen.cc
  • bf.exists 判断某个元素是否在过滤器中:bf.exists urls https://jaychen.cc

上面说过布隆过滤器存在误判的情况,在 redis 中有两个值决定布隆过滤器的准确率:

  • error_rate :允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间也就越大。
  • initial_size :布隆过滤器可以储存的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。

redis 中有一个命令可以来设置这两个值:

bf.reserve urls 0.01 100

三个参数的含义:

  • 第一个值是过滤器的名字。
  • 第二个值为 error_rate 的值。
  • 第三个值为 initial_size 的值。

使用这个命令要注意一点:执行这个命令之前过滤器的名字应该不存在,如果执行之前就存在会报错:(error) ERR item exists

相关文章:

  • json字符串 转换为数组
  • 用mpvue开发微信小程序
  • hadoop副本放置策略
  • 【逆序对】N*M Puzzle / Simple Puzzle
  • JavaCV cvEstimateRigidTransform函数使用心得
  • 10.17_T1 平津战役
  • EOS开发完全解析(二):用cleos命令行创建、导入、解锁钱包
  • 返回一个二维整数数组中最大子数组的和
  • 1、jeecg 笔记开篇
  • 论文笔记:Visual Semantic Navigation Using Scene Priors
  • InlineHookPsTerminateProcess(0环)
  • 人工智能会改变世界?那这项技能你必须要掌握了。
  • 如何洞悉城市人群移动规律?DataV海量轨迹可视化实践解析
  • webpack4 正确的配置方式
  • 5s管理推进的三个阶段及三大实施原则
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 30秒的PHP代码片段(1)数组 - Array
  • create-react-app做的留言板
  • Git 使用集
  • Objective-C 中关联引用的概念
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • 构建工具 - 收藏集 - 掘金
  • 缓存与缓冲
  • 聚类分析——Kmeans
  • 手机端车牌号码键盘的vue组件
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 学习Vue.js的五个小例子
  • 学习笔记:对象,原型和继承(1)
  • 用Visual Studio开发以太坊智能合约
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #QT(TCP网络编程-服务端)
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (NSDate) 时间 (time )比较
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (接口自动化)Python3操作MySQL数据库
  • (南京观海微电子)——I3C协议介绍
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • .net 发送邮件
  • .net开发时的诡异问题,button的onclick事件无效
  • .NET序列化 serializable,反序列化
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • @ModelAttribute注解使用
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • [ CTF ]【天格】战队WriteUp- 2022年第三届“网鼎杯”网络安全大赛(青龙组)
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林
  • [Assignment] C++1
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步