2 Redis的高级数据结构
1、Bitmaps
首先,最经典的应用场景就是用户日活的统计,比如说签到等。
字段串:“dbydc”,根据对应的ASCII表,最后可以得到对应的二进制,如图所示
一个字符占8位(bit),不够就在最高位补 0(零),我们只需设置值为 1 的位。如图所示,二进制最高位是在最左边的,但数组索引最高位是在最右边。字符“d”只需在偏移量(offset,即数组索引)第 1、2、5 位设置 1 ;字符“b”只需在偏移量(offset,即数组索引)第 9、10、14 位设置 1 ;字符“y”只需在偏移量(offset,即数组索引)第 17、18、19、20、23 位设置 1 ;字符“d”只需在偏移量(offset,即数组索引)第 25、26、29 位设置 1 ;字符“c”只需在偏移量(offset,即数组索引)第 33、34、38、39 位设置 1 。
- 字符“d”存储(第 1、2、5 位设置1)
127.0.0.1:6379> setbit mykey 1 1(integer) 0
127.0.0.1:6379> setbit mykey 2 1(integer) 0
127.0.0.1:6379> setbit mykey 5 1(integer) 0
- 字符“b”存储(第 9、10、14 位设置1)
127.0.0.1:6379> setbit mykey 9 1
(integer) 0
127.0.0.1:6379> setbit mykey 10 1
(integer) 0
127.0.0.1:6379> setbit mykey 14 1
(integer) 0
- 字符“y”存储(第 17、18、19、20、23 位设置1)
127.0.0.1:6379> setbit mykey 17 1(integer) 0127.0.0.1:6379> setbit mykey 18 1(integer) 0127.0.0.1:6379> setbit mykey 19 1(integer) 0127.0.0.1:6379> setbit mykey 20 1(integer) 0127.0.0.1:6379> setbit mykey 23 1(integer) 0
- 字符“d”存储(第 25、26、29 位设置1)
127.0.0.1:6379> setbit mykey 25 1(integer) 0127.0.0.1:6379> setbit mykey 26 1(integer) 0127.0.0.1:6379> setbit mykey 29 1(integer) 0
- 字符“c”存储(第 33、34、38、39 位设置1)
127.0.0.1:6379> setbit mykey 33 1(integer) 0127.0.0.1:6379> setbit mykey 34 1(integer) 0127.0.0.1:6379> setbit mykey 38 1(integer) 0127.0.0.1:6379> setbit mykey 39 1(integer) 0
- 获取键 mykey 对应的值
127.0.0.1:6379> get mykey“dbydc”
所以,我们在统计某位用户系统签到的时候,sign=1就是签到,0就是没有签到。
setbit 2023-jack-sign 1 1 //第一日签到
setbit 2023-jack-sign 2 0 //第二日未签到
setbit 2023-jack-sign 3 1 //第三日签到
...
统计出全年的签到次数:
127.0.0.1:6379> BITCOUNT 2023-jack-sign 0 3 #统计1的数量
(integer) 2
2、布隆过滤器与Bitmaps
1970 年布隆提出了一种布隆过滤器的算法,目的是用来判断一个元素是否在一个集合中。
算法由一个二进制数组和一个 Hash 算法组成
布隆过滤器的误判问题?
布隆过滤器的使用场景之缓存穿透
当用户查询的时候,缓存中的key不存在,则进行数据库的大量查询导致的数据库的崩溃场景.
解决思路:在查询的时候快速判断查询的用户是否存在有效的缓存数据,布隆过滤器。
解决缓存穿透的问题,所以在用户查询缓存没有命中的时候,需要兜底去查询数据库,因此redis是无法完全取代数据库的。
3、布隆过滤器的代码实现
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.nengxing</groupId><artifactId>redis-base</artifactId><version>0.0.1-SNAPSHOT</version><name>redis-base</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><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><!-- https://mvnrepository.com/artifact/redis.clients/jedis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.6.3</version></dependency><!--引入Redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-redis</artifactId><version>1.4.2.RELEASE</version></dependency><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.3</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1.1-jre</version></dependency><dependency><!-- this is needed or IntelliJ gives junit.jar or junit-platform-launcher:1.3.2 not found errors --><groupId>org.junit.platform</groupId><artifactId>junit-platform-launcher</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
布隆过滤器核心代码
import com.google.common.hash.Funnels;
import com.google.common.hash.Hashing;
import com.google.common.primitives.Longs;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;import java.nio.charset.Charset;/*仿Google的布隆过滤器实现,基于redis支持分布式*/
public class RedisBloomFilter {public final static String RS_BF_NS = "rbf:";private int numApproxElements; /*预估元素数量,在配合使用数组的时候使用*/private double fpp; /*布隆过滤器所能接受的最大误差*/private int numHashFunctions; /*自动计算的hash函数个数*/private int bitmapLength; /*自动计算的最优Bitmap长度*/@Autowiredprivate JedisPool jedisPool;/*** 构造布隆过滤器* @param numApproxElements 预估元素数量* @param fpp 可接受的最大误差* @return*/public RedisBloomFilter init(int numApproxElements,double fpp){this.numApproxElements = numApproxElements;this.fpp = fpp;/*位数组的长度*///this.bitmapLength = (int) (-numApproxElements*Math.log(fpp)/(Math.log(2)*Math.log(2)));this.bitmapLength=128;/*算hash函数个数,此处为了简便直接写死*///this.numHashFunctions = Math.max(1, (int) Math.round((double) bitmapLength / numApproxElements * Math.log(2)));this.numHashFunctions=2;return this;}/*** 计算一个元素值哈希后映射到Bitmap的哪些bit上* 用两个hash函数来模拟多个hash函数的情况* * @param element 元素值* @return bit下标的数组*/private long[] getBitIndices(String element){long[] indices = new long[numHashFunctions];/*会把传入的字符串转为一个128位的hash值,并且转化为一个byte数组*/byte[] bytes = Hashing.murmur3_128().hashObject(element, Funnels.stringFunnel(Charset.forName("UTF-8"))).asBytes();long hash1 = Longs.fromBytes(bytes[7],bytes[6],bytes[5],bytes[4],bytes[3],bytes[2],bytes[1],bytes[0]);long hash2 = Longs.fromBytes(bytes[15],bytes[14],bytes[13],bytes[12],bytes[11],bytes[10],bytes[9],bytes[8]);/*用这两个hash值来模拟多个函数产生的值*/long combinedHash = hash1;for(int i=0;i<numHashFunctions;i++){//数组下标indices[i]=(combinedHash&Long.MAX_VALUE) % bitmapLength;combinedHash = combinedHash + hash2;}System.out.print(element+"数组下标");for(long index:indices){System.out.print(index+",");}System.out.println(" ");return indices;}/*** 插入元素** @param key 原始Redis键,会自动加上前缀* @param element 元素值,字符串类型* @param expireSec 过期时间(秒)*/public void insert(String key, String element, int expireSec) {if (key == null || element == null) {throw new RuntimeException("键值均不能为空");}//为了与redis中的其他key进行区别String actualKey = RS_BF_NS.concat(key);try (Jedis jedis = jedisPool.getResource()) {try (Pipeline pipeline = jedis.pipelined()) {for (long index : getBitIndices(element)) {pipeline.setbit(actualKey, index, true);}pipeline.syncAndReturnAll();} catch (Exception ex) {ex.printStackTrace();}jedis.expire(actualKey, expireSec);}}/*** 检查元素在集合中是否(可能)存在** @param key 原始Redis键,会自动加上前缀* @param element 元素值,字符串类型*/public boolean mayExist(String key, String element) {if (key == null || element == null) {throw new RuntimeException("键值均不能为空");}String actualKey = RS_BF_NS.concat(key);boolean result = false;try (Jedis jedis = jedisPool.getResource()) {try (Pipeline pipeline = jedis.pipelined()) {for (long index : getBitIndices(element)) {pipeline.getbit(actualKey, index);}result = !pipeline.syncAndReturnAll().contains(false);} catch (Exception ex) {ex.printStackTrace();}}return result;}@Overridepublic String toString() {return "RedisBloomFilter{" +"numApproxElements=" + numApproxElements +", fpp=" + fpp +", numHashFunctions=" + numHashFunctions +", bitmapLength=" + bitmapLength +'}';}
}
判断不在的,一定不在,判断在的情况,大概率都不在,除非存在一定的hash冲突
测试:
@SpringBootTest
public class TestRedisBloomFilter {private static final int DAY_SEC = 60 * 60 * 24;@Autowiredprivate RedisBloomFilter redisBloomFilter;@Testpublic void testInsert() throws Exception {// System.out.println(redisBloomFilter);redisBloomFilter.insert("bloom:user", "20210001", DAY_SEC);redisBloomFilter.insert("bloom:user", "20210002", DAY_SEC);redisBloomFilter.insert("bloom:user", "20210003", DAY_SEC);redisBloomFilter.insert("bloom:user", "20210004", DAY_SEC);redisBloomFilter.insert("bloom:user", "20210005", DAY_SEC);}@Testpublic void testMayExist() throws Exception {System.out.println(redisBloomFilter.mayExist("bloom:user", "20210001"));System.out.println(redisBloomFilter.mayExist("bloom:user", "20210002"));System.out.println(redisBloomFilter.mayExist("bloom:user", "20210003"));System.out.println(redisBloomFilter.mayExist("bloom:user", "20211001"));}}
Guava的布隆
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;/*单机下无Redis的布隆过滤器:使用Google的Guava的BloomFilter*/
public class GuavaBF {public static void main(String[] args) {long expectedInsertions = 100000;double fpp = 0.00005;BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), expectedInsertions, fpp);bloomFilter.put("10081");bloomFilter.put("10082");bloomFilter.put("10083");bloomFilter.put("10084");bloomFilter.put("10085");bloomFilter.put("10086");System.out.println("123456:BF--"+bloomFilter.mightContain("123456"));//falseSystem.out.println("10086:BF--"+bloomFilter.mightContain("10086"));//trueSystem.out.println("10084:BF--"+bloomFilter.mightContain("10084"));//true}
}
基于Redisson的实现
import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/*Redisson底层基于位图实现了一个布隆过滤器,使用非常方便*/
public class RedissonBF {public static void main(String[] args) {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");//构造RedissonRedissonClient redisson = Redisson.create(config);RBloomFilter<String> bloomFilter = redisson.getBloomFilter("phoneList");//初始化布隆过滤器:预计元素为100000000L,误差率为3%bloomFilter.tryInit(100000000L,0.03);//将号码10081~10086插入到布隆过滤器中bloomFilter.add("10081");bloomFilter.add("10082");bloomFilter.add("10083");bloomFilter.add("10084");bloomFilter.add("10085");bloomFilter.add("10086");//判断下面号码是否在布隆过滤器中System.out.println("123456:BF--"+bloomFilter.contains("123456"));//falseSystem.out.println("10086:BF--"+bloomFilter.contains("10086"));//trueSystem.out.println("10084:BF--"+bloomFilter.contains("10084"));//true}
}
布隆过滤器的实现:
Redis + Redisson
Redis + 自主实现
无Redis + Guava
相关文章:

2 Redis的高级数据结构
1、Bitmaps 首先,最经典的应用场景就是用户日活的统计,比如说签到等。 字段串:“dbydc”,根据对应的ASCII表,最后可以得到对应的二进制,如图所示 一个字符占8位(bit),…...

Hive默认分割符、存储格式与数据压缩
目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限(ROW FORMAT)配置标准HQL为: ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

update_engine-FilesystemVerifierAction和PostinstallRunnerAction
在介绍完了DownloadAction之后,还剩下FilesystemVerifierAction和PostinstallRunnerAction,下面开始对其进行分析。 FilesystemVerifierAction 在数据下载完成后,在DownloadAction中会切换到FilesystemVerifierAction void DownloadAction:…...

深度学习乳腺癌分类 计算机竞赛
文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度,召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…...

【Python百宝箱】掌握Python Web开发三剑客:Flask、Django、FastAPI一网打尽
前言 在当今互联网时代,Web应用的开发变得愈发重要和复杂。选择一个合适的Web框架,掌握安全性与认证、数据库与ORM库、前端框架与交互、测试与调试工具等关键知识点,是每个Web开发者都必须面对的挑战。本文将带你深入了解三个流行的Python W…...

【人工智能时代的刑法体系与责任主体概述】
第一节:引言 随着科技的快速发展,人工智能 (Artificial Intelligence, AI) 正日益成为我们生活中不可或缺的一部分。从自动驾驶汽车到语音助手,从智能家居到金融机器人,AI 的广泛应用正不断改变着我们的生活方式和社会结构。然而…...

透视maven打包编译正常,intellj idea编译失败问题的本质
前言 maven多模块类型的项目,在Java的中大型应用中非常常见, 在 module 很多的情况,经常会出现各种各样的编辑依赖错误问题,今天记录一种比较常见的 case : A 子模块依赖 B 子模块,在 Terminal 上终端上 …...

npm报错
npm报错 npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! npm ERR! For a full report s…...

【FFmpeg实战】ffmpeg播放器-音视频解码流程
音视频介绍 音视频解码流程 FFmpeg解码的数据结构说明 AVFormatContext:封装格式上下文结构体,全局结构体,保存了视频文件封装格式相关信息AVInputFormat:每种封装格式,对应一个该结构体AVStream[0]:视频文件中每个视频ÿ…...

基于SSM的高校毕业选题管理系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...

一个简单的Oracle Redaction实验
本实验包含了: 简单的Oracle Redaction演示针对指定用户的Redaction 实验环境 假设有一个19c多租户数据库,PDB名为orclpdb1。 我们将在orclpdb1中建立2个用户: redact_user: redact管理员schema_user: schema用户 基础实验 首先进入数…...

getchar函数的功能有哪些
getchar函数是C语言标准库中的一个函数,主要用于从标准输入(通常是键盘)获取一个字符。它的功能包括: 从标准输入获取一个字符:getchar函数会等待用户输入一个字符,然后将其返回给程序。可以通过控制台输入…...

信息机房监控系统(动环辅助监控系统)
信息机房监控系统是一个综合性的系统,用于对机房的所有设备及其环境进行集中监控和管理。这种系统主要针对机房的各个子系统进行监控,包括动力系统、环境系统、消防系统、保安系统、网络系统等。 依托电易云-智慧电力物联网,以下是信息机房监…...

最强英文开源模型Llama2架构与技术细节探秘
prerequisite: 最强英文开源模型LLaMA架构探秘,从原理到源码 Llama2 Meta AI于2023年7月19日宣布开源LLaMA模型的二代版本Llama2,并在原来基础上允许免费用于研究和商用。 作为LLaMA的延续和升级,Llama2的训练数据扩充了40%,达到…...

编程刷题网站以及实用型网站推荐
1、牛客网在线编程 牛客网在线编程https://www.nowcoder.com/exam/oj?page1&tab%E8%AF%AD%E6%B3%95%E7%AF%87&topicId220 2、力扣 力扣https://leetcode.cn/problemset/all/ 3、练码 练码https://www.lintcode.com/ 4、PTA | 程序设计类实验辅助教学平台 PTA | 程…...

基于STC12C5A60S2系列1T 8051单片机的SPI总线器件数模芯片TLC5615实现数模转换应用
基于STC12C5A60S2系列1T 8051单片的SPI总线器件数模芯片TLC5615实现数模转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍SPI总线器件数模芯片TLC5615介绍通过按…...

【并发编程】Synchronized的使用
📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于…...

【Python】Python基础
文章目录 一、字面值常量和表达式二、变量2.1 定义变量2.2 变量的命名规则2.3 变量的类型2.4 不同类型大小2.5 动态类型 三、注释四、输入与输出五、运算符5.1 算术运算符5.2 关系运算符5.3 逻辑运算符5.4 赋值运算符 一、字面值常量和表达式 print(1 2 * 3) # 7 print(1 2 …...

gitlab环境准备
1.准备环境 gitlab只支持linux系统,本人在虚拟机下使用Ubuntu作为操作系统,gitlab镜像要使用和操作系统版本对应的版本,(ubuntu18.04,gitlab-ce_13.2.3-ce.0_amd64 .deb) book100ask:/$ lsb_release -a No LSB modules are available. Dist…...

Apache Doris (五十四): Doris Join类型 - Bucket Shuffle Join
🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录...

【AI】行业消息精选和分析(23-11-20)
技术发展 🎨 LCM即时绘画,体验所见所得: - LCM LoRA支持即时绘图生成,体验直观。 - 在线体验地址提供直接访问。 - 清华大学SimianLuo开发,加速稳定扩散模型运行。 💊 VM Pill:可吞咽装置追踪生…...

Matplotlib实现Label及Title都在下方的最佳姿势
Matplotlib实现Label及Title都在下方的最佳姿势 1. 问题背景2. 基本思想(可以不看)3. 方法封装4. 调用实例5. 总结6. 起飞 1. 问题背景 用python绘制下面这种图的时候,一般用xlable作为子图的标题,这是因为plt.title()方法绘制的…...

使用 uWSGI 部署 Django 应用详解
概要 部署 Django 应用到生产环境是一个至关重要的步骤,其中选择合适的 WSGI 服务器对于确保应用的稳定性和性能至关重要。uWSGI 是一个流行的选择,它不仅高效、轻量,还非常灵活。本文将详细介绍如何使用 uWSGI 来部署 Django 应用ÿ…...

MyBatis在注解中使用动态查询
以前为了使用注解并在注解中融入动态查询,会使用Provider。后来发现只要加入"<script>包含动态查询的SQL语句</script>"就可以了。 例如: Select("<script>" "select v.*,u.avatar,u.nickname from videos…...

百云齐鲁 | 云轴科技ZStack成功实践精选(山东)
山东省作为我国重要的工业基地和北方地区经济发展的战略支点,在“十四五”规划中将数字强省建设分为数字基础设施、数字科技、数字经济、数字政府、数字社会、数字生态六大部分,涵盖政治、经济、民生等多个方面,并将大数据、云计算、人工智能…...

【Electron】electron-builder打包失败问题记录
文章目录 yarn下载的包不支持require()winCodeSign-2.6.0.7z下载失败nsis-3.0.4.1.7z下载失败待补充... yarn下载的包不支持require() 报错内容: var stringWidth require(string-width)^ Error [ERR_REQUIRE_ESM]: require() of ES Module /stuff/node_modules/…...

OpenCV快速入门:直方图、掩膜、模板匹配和霍夫检测
文章目录 前言一、直方图基础1.1 直方图的概念和作用1.2 使用OpenCV生成直方图1.3 直方图归一化1.3.1 直方图归一化原理1.3.2 直方图归一化公式1.3.3 直方图归一化代码示例1.3.4 OpenCV内置方法:normalize()1.3.4.1 normalize()方法介绍1.3.4.2 normalize()方法参数…...

HDD与QLC SSD深度对比:功耗与存储密度的终极较量
在当今数据世界中,存储设备的选择对于整体系统性能和能耗有着至关重要的影响。硬盘HDD和大容量QLC SSD是两种主流的存储设备,而它们在功耗方面的表现是许多用户关注的焦点。 扩展阅读: 1.面对SSD的步步紧逼,HDD依然奋斗不息 2.…...

医疗软件制造商如何实施静态分析,满足 FDA 医疗器械网络安全验证
随着 FDA 对网络安全验证和标准提出更多要求,医疗软件制造商需要采用静态分析来确保其软件满足这些新的安全标准。继续阅读以了解如何实施静态分析来满足这些安全要求。 随着 FDA 在其软件验证指南中添加更多网络安全要求,医疗设备制造商可以转向静态分…...

【设计模式】聊聊策略模式
策略模式的本质是为了消除if 、else代码,提供拓展点,对拓展开放,对修改关闭,也就是说我们开发一个功能的时候,要尽量的采用设计模式进行将不变的东西进行抽取出来,将变化的东西进行隔离开来,这样…...