Redis:新的3种数据类型Bitmaps、HyperLoglog、Geographic

目录

  • Bitmaps
    • 简介
    • 常用命令
    • bitmaps与set比较
  • HyperLoglog
    • 简介
    • 命令
  • Geographic
    • 简介
    • 命令

Bitmaps

简介

位操作字符串。

现代计算机使用二进制(位)作为信息的基本单位,1个字节等于8位,例如“abc”字符串是有3个字节组成,但实际在计算机内存储时将其使用二进制表示,“abc”分别对应的ASCII码是:97、98、99,对应的二进制分别是01100001、01100010、01100011,如下图
在这里插入图片描述

合理地使用位操作能够有效地提高内存使用率和开发效率。

Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:

  • Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作,字符串中每个字符对应1个字节,也就是8位,一个字符可以存储8个bit位信息。
  • Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。

在这里插入图片描述

常用命令

  1. setbit

设置某个偏移量的值(0或1)。

SETBIT key offset value

设置offset偏移位的值为value,offset的值是从0开始的,n代表第n+1个bit位置的。
offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
value 的值只能为0或1

**返回值:**指定偏移量原来储存的位。

示例:

redis> SETBIT bit 10086 1 
(integer) 0 
redis> GETBIT bit 10086 
(integer) 1 
redis> GETBIT bit 100 # bit 默认被初始化为 0 
(integer) 0

例如每个独立用户是否访问过网站存放在bitmaps中,将访问的用户记做1,没有访问的用户记做0,用户id作为offset。

假设现在有20个用户,userid=1,6,11,15,19的用户对网站进行了访问,那么当前bitmaps初始化结果如图
在这里插入图片描述

users:20220409 这个bitmaps中表示2022-04-09这天独立访问的用户,如下

127.0.0.1:6379> setbit users:20220409 1 1 
(integer) 0 
127.0.0.1:6379> setbit users:20220409 6 1 
(integer) 0 
127.0.0.1:6379> setbit users:20220409 11 1 
(integer) 0 
127.0.0.1:6379> setbit users:20220409 15 1 
(integer) 0 
127.0.0.1:6379> setbit users:20220409 19 1 
(integer) 0
  1. getbit

获取某个偏移位的值.

GETBIT key offset

获取key所对应的bitmaps中offset偏移位的值。

返回值:0或者1

示例

127.0.0.1:6379> setbit users 1001 1 #设置偏移量1001的bit位的值为1 
(integer) 0 
127.0.0.1:6379> getbit users 1001 #获取偏移位1001的bit位的值 
(integer) 1 
127.0.0.1:6379> getbit users 1000 #获取偏移位1000的bit位的值,未设置,返回0 
(integer) 0
  1. bitcount

统计bit位都为1的数量

BITCOUNT key [start] [end]

统计字符串被设置为1的bit数,一般情况下,给定的整个字符串都会被进行统计,通过指定额外的

start或者end参数,可以让计数只在特定的位上进行, start 和 end 参数,都可以使用负数值:

比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。

注意了:start、end是指bit组的字节的下标数,一个直接对应8个bit,所以[a,b]对应的offset范围是[8a,8b+7]

示例:

127.0.0.1:6379> setbit user 7 1 # 设置user这个bitmaps中偏移量为7的bit为值为1,也就是第8 个bit位的值 
(integer) 0 
127.0.0.1:6379> setbit user 15 1 # 设置user这个bitmaps中偏移量为15的bit为值为1 
(integer) 0 
127.0.0.1:6379> setbit user 23 1 # 设置user这个bitmaps中偏移量为23的bit为值为1 
(integer) 0 
127.0.0.1:6379> bitcount user # 获取user这个bitmaps中1的数量 
(integer) 3 
127.0.0.1:6379> bitcount user 0 1 # 获取[0,1]这个字节内bit位上1的数量,也就是offset是 [0,15]的位置上1的数量,所以是2个 
(integer) 2 
127.0.0.1:6379> bitcount user 0 0 # 获取[0,0]这个字节内bit位上1的数量,也就是offset是 [0,7]的位置上1的数量,只有7这个位置,所以是1个 
(integer) 1
  1. bittop

对一个多个bitmaps执行位操作。

BITOP operation destkey key [key ...]

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。

operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:

  • BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到destkey 。
  • BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到destkey 。
  • BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到destkey 。
  • BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。

除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。

**返回值:**保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。

示例

redis> SETBIT bits-1 0 1 # bits-1 = 1001 
(integer) 0 
redis> SETBIT bits-1 3 1 
(integer) 0 
redis> SETBIT bits-2 0 1 # bits-2 = 1011 
(integer) 0 
redis> SETBIT bits-2 1 1 
(integer) 0 
redis> SETBIT bits-2 3 1 
(integer) 0 
redis> BITOP AND and-result bits-1 bits-2 
(integer) 1
redis> GETBIT and-result 0      # and-result = 1001
(integer) 1
redis> GETBIT and-result 1 
(integer) 0 
redis> GETBIT and-result 2 
(integer) 0 
redis> GETBIT and-result 3 
(integer) 1

bitmaps与set比较

假设网站有 1 亿用户, 每天独立访问的用户有 5 千万, 如果每天用集合类型和 Bitmaps 分别存储活跃用户可以得到表

set 和 Bitmaps 存储一天活跃用户对比

在这里插入图片描述

很明显, 这种情况下使用 Bitmaps 能节省很多的内存空间, 尤其是随着时间推移节省的内存还是非常可观的。

set Bitmaps 存储独立用户空间对比

在这里插入图片描述

但 Bitmaps 并不是万金油, 假如该网站每天的独立访问用户很少, 例如只有 10 万(大量的僵尸用户), 那么两者的对比如下表所示, 很显然, 这时候使用 Bitmaps 就不太合适了, 因为基本上大部分位都是 0。

在这里插入图片描述

HyperLoglog

简介

在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站 PV(PageView 页面访问量),可以使用 Redis 的 incr、incrby 轻松实现。但像 UV(UniqueVisitor 独立访客)、独立 IP 数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。

解决基数问题有很多种方案:

数据存储在 MySQL 表中,使用 distinct count 计算不重复个数。

使用 Redis 提供的 hash、set、bitmaps 等数据结构来处理。

以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。能否能够降低一定的精度来平衡存储空间?Redis 推出了 HyperLogLog。

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是:在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog 不能像集合那样,返回输入的各个元素。

什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8},那么这个数据集的基数集为 {1, 3, 5 ,7, 8},基数 (不重复元素) 为 5。 基数估计就是在误差可接受的范围内,快速计算基数。

命令

  1. pfadd

添加多个元素。

pfadd key element [element ...]

向HyperLoglog类型的key中添加一个或者多个元素。添加一个或者多个元素到key对应的集合中。

**返回值:**1:添加成功;0:添加失败

示例

127.0.0.1:6379> pfadd program java php c c++ # program中添加4个元素 [java,php,c,c++],添加成功发,返回1 
(integer) 1 
127.0.0.1:6379> pfadd program java # 再次添加java,由于已经存在,所以添加失败,返回0 
(integer) 0 
127.0.0.1:6379> pfadd program java js # 再次添加2个元素,java已经存在了,但是js不存在, 添加成功,返回1 
(integer) 1
  1. pfcount

获取多个HLL合并后元素的个数。

pfcount key1 key2 ...

统计一个或者多个key去重后元素的数量。

示例

127.0.0.1:6379> pfadd uv1 a b c d e #uv1中5个元素:[a,b,c,d,e] 
(integer) 1 
127.0.0.1:6379> pfcount uv1 #uv1中数量为5 
(integer) 5 
127.0.0.1:6379> pfadd uv2 b c d e f #uv2中5个元素:[b,c,d,e,f] 
(integer) 1 
127.0.0.1:6379> pfcount uv2 #uv2中数量为5
(integer) 5 
127.0.0.1:6379> pfcount uv1 uv2 # 获取uv1和uv2去重之后数量合集:[a,b,c,d,e,f],数量为5 
(integer) 5
  1. pfmerge

将多个HLL合并后元素放入另外一个HLL

pfmerge destkey sourcekey [sourcekey ...]

将多个 sourcekey 合并后放到 destkey 中。

示例

127.0.0.1:6379> pfadd uv1 a b c d e #uv1中5个元素:[a,b,c,d,e] 
(integer) 1 
127.0.0.1:6379> pfcount uv1 #uv1中数量为5 
(integer) 5 
127.0.0.1:6379> pfadd uv2 b c d e f #uv2中5个元素:[b,c,d,e,f] 
(integer) 1 
127.0.0.1:6379> pfcount uv2 #uv2中数量为5 
(integer) 5 
127.0.0.1:6379> pfmerge uv_dest uv1 uv2 #将uv1和uv2合并后放入uv_dest 
OK
127.0.0.1:6379> pfcount uv_dest #uv_dest元素个数为6 
(integer) 6

Geographic

简介

Reids3.2 中增加了对GEO类型的支持,GEO(Geographic),地理信息的缩写。该类型,就是元素的 2 维坐标,在地图上就是经纬度,redis基于该类型,提供了经纬度设置、查询、范围查询、距离查询,经纬度Hash等常见操作。

命令

  1. geoadd

添加多个位置的经纬度。

geoadd key longitude latitude member [longitude latitude member ...]

longitude latitude member:经度 纬度 名称

示例

127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai #添加上海的经纬度 
(integer) 1 
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing #添加重庆、深圳、北京 3 个城市的经纬度 
(integer) 3 
127.0.0.1:6379> type china:city #发现geo实际上使用zset类型存储的 
zset 
127.0.0.1:6379> zrange china:city 0 -1 
1) "chongqing" 2) "shenzhen" 3) "shanghai" 4) "beijing" 
127.0.0.1:6379> zrange china:city 0 -1 withscores 
1) "chongqing" 2) "4026042091628984" 3) "shenzhen" 4) "4046432193584628" 5) "shanghai" 6) "4054803462927619" 7) "beijing" 8) "4069885332386336"

两级无法直接添加,一般会下载城市数据,直接通过java程序一次性导入。

有效的经纬度从-180度到180度,有效的维度从-85.05112878度到85.05112878度。

当坐标位置超出指定范围时,该命令将会返回一个错误。

已经添加的数据,是无法再次往里面添加的。

  1. geopos

获取多个位置的坐标值

geopos key member [member ...]

示例

127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai #添加上海的经纬度 
(integer) 1 
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing #添加重庆、深圳、北京 3 个城市的经纬度 
(integer) 3 
127.0.0.1:6379> geopos china:city wuhan beijing chongqing #获取武汉、北京、重庆 3个城 市的坐标,由于没有添加武汉的数据,所以没有获取到,其他2个获取到了 
1) (nil) 
2) 
	1) "116.38000041246414185" 
	2) "39.90000009167092543"
3) 
  1) "106.49999767541885376" 
  2) "29.52999957900659211"
  1. geodist

获取两个位置的直线距离

geodist key member1 member2 [m|km|ft|mi]

单位:[m|km|ft|mi] -》[米|千米|英里|英尺],默认为米

示例

127.0.0.1:6379> geoadd china:city 
121.47 31.23 shanghai #添加上海的经纬度 
(integer) 1 
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing #添加重庆、深圳、北京 3 个城市的经纬度 
(integer) 3
127.0.0.1:6379> geodist china:city beijing chongqing km #获取北京到重庆的直线距离 
"1462.9505"
  1. georadius

以给定的经纬度为中心,找出某一半径内的元素

georadius key longitude latitude radius m|km|ft|mi

单位:[m|km|ft|mi] -》[米|千米|英里|英尺],默认为米

示例

127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai #添加上海的经纬度 
(integer) 1 
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing #添加重庆、深圳、北京 3 个城市的经纬度
(integer) 3 
127.0.0.1:6379> georadius china:city 110 30 1000 km #在china:city中检索:以经纬度 (110,30)为中心,半径为1000km内的位置列表 
1) "chongqing" 
2) "shenzhen"

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【面试经典150 | 数学】Pow(x, n)

文章目录 写在前面Tag题目来源题目解读解题思路方法一:快速幂-递归方法二:快速幂-迭代 其他语言python3 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主…

一文总结MySQL的指令是如何工作的

当你输入一条MySQL指令时候有没有想过会发生什么? 建立连接 首先你得先连到数据库上才行,这又分为长连接和短链接,短链接就是你查询一次就断开连接,长连接是你可以多次查询直到主动断开连接(也可能被杀死进程&#x…

基于单片机音乐弹奏播放DS1302万年历显示及源程序

一、系统方案 1、本设计采用51单片机作为主控器。 2、DS1302计时显示年月日时分秒。 3、按键可以弹奏以及播放音乐,内置16首音乐。 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 /时钟显示**/ void init_1602_ds1302() { write…

RabbitMQ 集群和镜像队列

文章目录 一、clustering(集群)1、使用集群的原因2、搭建步骤2.1、拉取镜像2.2、创建三个RabbitMQ容器节点2.3、集群搭建 二、镜像队列1、使用镜像的原因2、搭建步骤 总结 一、clustering(集群) 1、使用集群的原因 如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等…

string类的总结

目录 1.为什么要学习string类 2.string的标准库 3.string类的常用接口说明 1.string类对象的常见构造 2.string类对象的容量操作 3.string类对象的3种遍历方法 3.1 [ ] 下标 3.2 基于范围的for循环 3.3 迭代器 4 string类对象的元素访问 4.1 operator[]: 4.…

【LearnOpenGL基础入门——3】绘制纯色三角形

目录 一.写在前面 二.顶点输入 三.顶点着色器 四.编译着色器 五.片段着色器 六.着色器程序 七.链接顶点属性 彩蛋 一.写在前面 我们先认识一下OpenGL常用的几个名词: 顶点数组对象:Vertex Array Object,VAO顶点缓冲对象:…

mysql客户端navicat的一些错误合集

关于mysql的客户端的使用的一些问题 问题描述: 在使用navicat prenium客户端的时候,连接数据库出现 Table ‘performance_schema.session_variables’ doesn’t exist 错误 解决方案: 首先找到mysql的bin目录 然后winR 进入到cmd界面 输入…

数据库迁移(DBeaver版本)

最近需要做一个数据库迁移, 测试环境开发的差不多了,需要将脚本迁移到生产。 中间了试了一些工具,比如Jetbrain出品的datagrip,这个数据库工具平时还是很好用的,但是数据迁移感觉不是那么好用,所以还是用到…

二元分类模型评估方法

文章目录 前言一、混淆矩阵二、准确率三、精确率&召回率四、F1分数五、ROC 曲线六、AUC(曲线下面积)七、P-R曲线类别不平衡问题中如何选择PR与ROC 八、 Python 实现代码混淆矩阵、命中率、覆盖率、F1值ROC曲线、AUC面积 指标 公式 意义 真正例 (TP)被…

图像分类系列(三) GoogLeNet InceptionV1学习详细记录

前言 ​ 在上一期中介绍了VGG,VGG在2014年ImageNet 中获得了定位任务第1名和分类任务第2名的好成绩,而今天要介绍的就是同年分类任务的第一名——GoogLeNet 。 ​ 作为2014年ImageNet比赛冠军,GoogLeNet 比VGG更深的网络,比Alex…

虹科示波器 | 汽车免拆检修 | 2015款奔驰G63AMG车发动机偶尔自动熄火

一、故障现象 一辆2015款奔驰G63AMG车,搭载157发动机,累计行驶里程约为9.4万km。车主反映,该车低速行驶时,发动机偶尔会自动熄火,故障大概1个星期出现1次。 二、故障诊断 接车后路试,故障未能再现。用故障检…

MyBatis查询数据库(全是精髓)

1. 什么是MyBatis? 简单说,MyBatis就是一个完成程序与数据库交互的工具,也就是更简单的操作和读取数据库的工具。 2. 怎么学习Mybatis Mybatis学习只分为两部分: 配置MyBatis开发环境使用MyBatis模式和语法操作数据库 3. 第一…

【Gradle构件工具深度学习】

Gradle构件工具深度学习 1. 课程大纲1.1 Gradle入门1.2 与Idea整合1.3 Gradle进阶 2. 常见项目构建工具3. 安装gradle 1. 课程大纲 1.1 Gradle入门 基本介绍、常用指令、项目目录、项目应用 1.2 与Idea整合 Groovy语法、整合IDEA、搭建web工程、项目部署 1.3 Gradle进阶 生命周…

springboot jar包 无法读取静态资源文件

springboot jar包 无法读取静态资源文件 参考 springboot项目读取resources目录下的文件的9种方式 Resource resource resourceLoader.getResource("classpath:static/jkbw/jkbw4.txt");try{InputStream inputStream resource.getInputStream();BufferedReader r…

基于知识图谱+flask的大数据电影问答系统(超详细讲解及源码)

大数据知识图谱项目——基于知识图谱flask的大数据电影问答系统(超详细讲解及源码) 一、项目概述 知识图谱是将知识连接起来形成的一个网络。由节点和边组成,节点是实体,边是两个实体的关系,节点和边都可以有属性。知…

基于秃鹰算法优化概率神经网络PNN的分类预测 - 附代码

基于秃鹰算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于秃鹰算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于秃鹰优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络的光滑…

Spring初识

未来的几周时间,大概率我会更新一下Spring家族的一些简单知识。而什么是Spring家族,好多同学还不是很清楚,我先来简单介绍一下吧: 所谓Spring家族,它其实就是一个框架,是基于Servlet再次进行封装的内容。为…

Redis篇---第六篇

系列文章目录 文章目录 系列文章目录前言一、Redis 为什么设计成单线程的?二、什么是 bigkey?会存在什么影响?三、熟悉哪些 Redis 集群模式?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,…

从0开始学习JavaScript--JavaScript 表达式与运算符

JavaScript中的表达式和运算符是构建逻辑、进行计算的基础。本文将深入研究JavaScript中各类表达式,包括算术表达式、关系表达式、逻辑表达式,以及运算符的使用方法,并通过丰富的示例代码来帮助读者更全面地了解和运用这些概念。 算术表达式…

【算法萌新闯力扣】:两个数组的交集

力扣热题:两个数组的交集 开篇 今天早上状态不错,花了较短的时间刷了4道力扣算法题。挑选了一道还不错的题目与大伙分享。 题目链接:349.两个数组的交集 题目描述 代码思路 看到题目后,想到可以把一个数组用集合存起来,然后用…