深入浅出Redis(十一):Redis四种高级数据结构:Geosptial、Hypeloglog、Bitmap、Bloom Filter布隆过滤器

引言

Redis提供丰富的数据结构来解决各种场景下的问题,前段时间的一篇文章深入浅出Redis(一):对象与数据结构已经深入浅出的说明Redis中的常用基础对象与数据结构

本篇文章将作为那篇文章的补充,深入浅出的解析另外四种数据结构:Geospatial、Hyperloglog、Bitmap以及Bloom Filter布隆过滤器

Geospatial

Geospatial 是一种能够解决地理空间相关场景下的数据结构,它提供的命令能够容易实现两地距离、附近的人等功能

Geospatial 使用GeoHash算法,底层实现使用zset对象 因此也可以使用Zset命令

geoadd 添加

geoadd key 经度 纬度 名称

将指定的地理空间位置(纬度、经度、名称)添加到指定的key中(可添加多个)

有效的经度从-180度到180度

有效的纬度从-85.05112878度到85.05112878度

超出上述经纬度会报错

 127.0.0.1:6379> geoadd china:city 116.23 40.22 beijing 
 (integer) 1
 127.0.0.1:6379> geoadd china:city 121.48 31.40 shanghai 113.88 22.55 shenzhen 104.10 30.65 chendu
 (integer) 3

geopos 获取

geopos key 成员名...

从key里返回所有给定位置元素的位置(经度和纬度)

 127.0.0.1:6379> geopos china:city beijing shenzhen
 1) 1) "116.23000055551528931"
    2) "40.2200010338739844"
 2) 1) "113.87999922037124634"
    2) "22.5500010475923105"

geodist 位置间的距离

geodist key member1 member2 [unit]

返回两个给定位置之间的距离

单位:(默认米):m 表示单位为米,km表示单位为千米,mi 表示单位为英里,ft 表示单位为英尺

 127.0.0.1:6379> geodist china:city beijing shenzhen
 "1977782.5112"
 127.0.0.1:6379> geodist china:city beijing shenzhen km
 "1977.7825"

georadius 以某点为中心,查找周围x半径之内的member(附近的人)

georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [count]

以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素

withcoord:获得经纬度坐标

withdist:找到的元素距离中心点的距离

count:限制查到的个数

 #以经纬度 110,30为中心,半径1500km的范围内的成员
 127.0.0.1:6379> georadius china:city 110 30 1500 km 
 1) "chendu"
 2) "shenzhen"
 3) "shanghai"
 4) "beijing"
 #以经纬度 110,30为中心,半径1500km的范围内的成员 列出成员坐标经纬度
 127.0.0.1:6379> georadius china:city 110 30 1500 km withcoord
 1) 1) "chendu"
    2) 1) "104.09999996423721313"
       2) "30.6499990746355806"
 2) 1) "shenzhen"
    2) 1) "113.87999922037124634"
       2) "22.5500010475923105"
 3) 1) "shanghai"
    2) 1) "121.48000091314315796"
       2) "31.40000025319353938"
 4) 1) "beijing"
    2) 1) "116.23000055551528931"
       2) "40.2200010338739844"
  #以经纬度 110,30为中心,半径1500km的范围内的成员 列出成员坐标经纬度和成员到中心直线距离
 127.0.0.1:6379> georadius china:city 110 30 1500 km withcoord withdist
 1) 1) "chendu"
    2) "570.9717"
    3) 1) "104.09999996423721313"
       2) "30.6499990746355806"
 2) 1) "shenzhen"
    2) "914.3335"
    3) 1) "113.87999922037124634"
       2) "22.5500010475923105"
 3) 1) "shanghai"
    2) "1108.3830"
    3) 1) "121.48000091314315796"
       2) "31.40000025319353938"
 4) 1) "beijing"
    2) "1269.3568"
    3) 1) "116.23000055551528931"
       2) "40.2200010338739844"
 #以经纬度 110,30为中心,半径1500km的范围内的成员 列出成员坐标经纬度 限制只查询一个(直线距离最近的)      
 127.0.0.1:6379> georadius china:city 110 30 1500 km withcoord count 1
 1) 1) "chendu"
    2) 1) "104.09999996423721313"
       2) "30.6499990746355806"
  #以经纬度 110,30为中心,半径1500km的范围内的成员 列出成员坐标经纬度 限制只查询俩个(直线距离最近的)  
 127.0.0.1:6379> georadius china:city 110 30 1500 km withcoord count 2
 1) 1) "chendu"
    2) 1) "104.09999996423721313"
       2) "30.6499990746355806"
 2) 1) "shenzhen"
    2) 1) "113.87999922037124634"
       2) "22.5500010475923105"

georadiusbymember (与georadius类似,它是以member为中心的)

georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [count]

这个命令和 georadius命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的

 #以beijing为中心 1500km为半径 查找的成员(会查到自己)
 127.0.0.1:6379> georadiusbymember china:city beijing 1500 km
 1) "shanghai"
 2) "beijing"

geohash

geohash key member...

该命令将返回11个字符的Geohash字符串

 # 深圳与成都
 127.0.0.1:6379> geohash china:city shenzhen chendu
 1) "ws0br3hgk20"
 2) "wm6n2gem1v0"
 ​
 # 东莞与深圳
 127.0.0.1:6379> geohash china:city dongguan shenzhen
 1) "ws0fuqwjpn0"
 2) "ws0br3hgk20"

将二维经纬度转化为一维字符串,如果俩个成员距离越近,字符串就会越相似

通过Zset指令来操作geo(因为geo底层实现原理就是Zset)

 127.0.0.1:6379> zrange china:city 0 -1
 1) "chendu"
 2) "shenzhen"
 3) "dongguan"
 4) "shanghai"
 5) "beijing"
 127.0.0.1:6379> zrem china:city dongguan
 (integer) 1
 127.0.0.1:6379> zrange china:city 0 -1
 1) "chendu"
 2) "shenzhen"
 3) "shanghai"
 4) "beijing"

Hyperloglog

在数据量特别大的情况下,想要统计数量可以选择用哈希表实现的set存储(能够去重),但是哈希表是空间换时间的数据结构,这种情况下会浪费大量空间

hyperloglog使用基数统计算法,用固定且少量的空间,能够实现统计计数,但缺点是有0.81%的错误率

A={1,2,4,5,6,1}

B={1,2,4,5,6}

基数=5(不重复的元素)

命令

  • 存: pfadd key element...将指定元素添加到hyperloglog
  • 读: pfcount key...统计hyperloglog中的基数数量(一个hyperloglog时)或并集数量(多个hyperloglog时)
  • 合并:pfmerge destkey sourcekey...将多个hyperloglog合并成一个hyperloglog并返回并集数量
 127.0.0.1:6379> pfadd mykey a b c d e f g 
 (integer) 1
 127.0.0.1:6379> pfcount mykey
 (integer) 7
 127.0.0.1:6379> pfadd mykey2 a b c d e f g h i j
 (integer) 1
 127.0.0.1:6379> pfcount mykey mykey2
 (integer) 10
 127.0.0.1:6379> pfmerge newkey mykey2  mykey
 OK
 127.0.0.1:6379> pfcount newkey
 (integer) 10

Bitmap

Bitmap使用位数组中的二进制来进行 状态统计 (只有 0 1)

Bitmap能够有效的大数据量下进行只有俩个状态的统计

比如:统计只有俩个状态的用户信息(活跃,不活跃。登录,未登录。打卡,未打卡)

使用

  • setbit key offset value设置key在offset处的bit值(0/1)

  • getbit key offset 获得key在offset处的bit值(0/1)

  • bitcount key 统计key中有多少位1

  • 模拟电影是否被点播情况 key->日期 offset->(电影ID)value->(0为未点播,1为点播)

    • 统计每天某部电影是否被点播 getbit 日期 电影ID
    • 统计每天有多少部电影被点播 bitcount 日期
    • 统计每周/月/年有多少部电影被点播 bitop or 每周日期 记录值后可统计每月,每年 或
    • 统计年度哪部电影没被点播 (为0时没被点播)
     127.0.0.1:6379> setbit 1130 1 1 #11月30日 1号电影 被点播
     (integer) 0
     127.0.0.1:6379> setbit 1130 2 1 #11月30日 2号电影 被点播
     (integer) 0
     127.0.0.1:6379> setbit 1130 3 1 #11月30日 3号电影 被点播
     (integer) 0
     127.0.0.1:6379> setbit 1201 4 1 #12月1日 4号电影 被点播
     (integer) 0
     127.0.0.1:6379> setbit 1201 5 1 #12月1日 5号电影 被点播
     (integer) 0
     127.0.0.1:6379> setbit 1201 1 1 #12月1日 1号电影 被点播
     (integer) 0
     ​
     127.0.0.1:6379> bitcount 1130 #11月30日 3部电影被点播
     (integer) 3
     127.0.0.1:6379> bitcount 1201 #12月1日 3部电影被点播
     (integer) 3
     127.0.0.1:6379> bitop and 1130-1201 1130 1200 #统计11月30日 与 12月1日 都点播了的电影
     (integer) 1
     127.0.0.1:6379> getbit 1130-1201 1 #2日都被点播的电影是1号电影
     (integer) 1
     127.0.0.1:6379> bitcount 1130-1201
     (integer) 1

原理

位数组使用sds来实现,sds是二进制安全的,sds存储时逆序存储位数组,逆序存储在扩容时不用修改老数据

(不了解sds的同学可以先看这篇文章深入浅出Redis(一):对象与数据结构)

setbit :先计算len是否需要扩容,再计算偏移量在哪个字节上,接着计算偏移量在哪个位上,修改那个位的值并返回旧的值

getbit :计算偏移量在哪个字节上,接着计算偏移量在哪个位上,再获取

bittop :and、or、xor都是新建sds 每个字节做位操作结果放入新建sds中 ;not 则是直接取反

bitcount : 数据量小于128位时使用查表,大于128位时使用每次循环4次 swar,每次swar可以计算32位;swar是将32位分成2bit一组与01 (计算低位)再右移一位继续与运算(计算高位),再依次分为4位、8位、16位一组依次操作(jdk的integer.bitcount也是swar算法)

Bloom Filter

布隆过滤器能够使用少量的空间来判断某个元素是否存在于集合中,但存在一定的误判率(不在集合中保存元素)

布隆过滤器适合在大数据场景下,允许一定误判的快速判断元素是否存在集合中

Bloom Filter用于判断元素是否重复在集合中,不保存元素数据,节省空间,有一定误差

原理

Bloom Filter由位数组和多个hash函数组成

image-20221209214507196.png

添加:将Key经过多个hash函数得到的索引,在位数组对应索引上设置为1

判断是否在集合中:将Key经过多个hash函数得到的索引,查看位数组对应索引上值是否为1,为1则可能存在(该索引上设置为1还有可能是添加其他Key设置的),如果值为0,那么该Key一定不存在集合中

布隆过滤器的误判率与空间大小有关,空间越小就越容易导致误判

使用

安装布隆过滤器插件

 #下载
 wget https://github.com/RedisLabsModules/rebloom/archive/v1.1.1.tar.gz
 #解压
 tar -zxvf v1.1.1.tar.gz
 cd rebloom-1.1.1
 #编译
 make

使用 bf.add添加 bf.exists判断是否存在集合中

 127.0.0.1:6379> bf.add bloomfilter cl
 (integer) 1
 127.0.0.1:6379> bf.add bloomfilter tcl
 (integer) 1
 127.0.0.1:6379> bf.exists bloomfilter cl
 (integer) 1
 127.0.0.1:6379> bf.exists bloomfilter cl1
 (integer) 0
 127.0.0.1:6379> bf.exists bloomfilter tcl
 (integer) 1

总结

本篇文章深入浅出的解析Redis中四种高级数据结构的使用、适用场景以及原理

Geospatial 使用Geohash算法以及zset对象实现,适用于计算地理空间的场景

Hypeloglog 使用少量固定空间以及基数统计算法,适用于大数据情况下能接收微小出错的统计场景

Bitmap 使用sds实现的位数组,sds逆序存储位数组扩容时不用修改旧数据,适用于大数据情况下只有两个状态的统计场景

Bloom Filter 使用位数组与多个哈希函数实现,适用于在大数据情况下且能接收微小出错的判断元素是否存在集合的场景

最后(一键三连求求拉~)

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

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

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

相关文章

“春招市场”鸿蒙岗位增长163%!你想活出怎样的代码人生?

前段时间“智联招聘崩了”登上微博热搜。不少网友都感叹,可想而知今年的就业压力有多大,找工作真的太难了…… 金三银四,大家的求职热情暴涨到服务器都承受不住,都想在1179万毕业生中脱颖而出,开年春招就已经热辣滚烫……

B站广告推广操作教程及费用?

哔哩哔哩(B站)作为国内极具影响力的年轻人文化社区,已成为众多品牌与企业触达目标受众、提升品牌影响力的重要阵地。然而,面对B站复杂的广告系统与精细化运营需求,许多广告主可能对如何高效开展B站广告推广感到困惑。云…

03-JAVA设计模式-组合模式

组合模式 什么是组合模式 组合模式(Composite Pattern)允许你将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端以统一的方式处理单个对象和对象的组合。组合模式让你可以将对象组合成树形结构,并且能像单独对象一…

Python零基础从小白打怪升级中~~~~~~~文件和文件夹的操作 (1)

第七节:文件和文件夹的操作 一、IO流(Stream) 通过“流”的形式允许计算机程序使用相同的方式来访问不同的输入/输出源。stream是从起源(source)到接收的(sink)的有序数据。我们这里把输入/输…

Llama 3下月正式发布,继续开源!

4月10日,Techcrunch消息,Meta在本周伦敦举办的一场活动中确定,下个月将正式发布Llama 3并且继续开源。 Meta全球事务总裁Nick Clegg表示,我们希望在下个月,甚至更短的时间内,正式推出新一代基础模型Llama …

[C语言][数据结构][链表] 单链表的从零实现!

目录 零.必备知识 1.一级指针 && 二级指针 2. 节点的成员列表 a.数据 b.指向下一个节点的指针. 3. 动态内存空间的开辟 (malloc-calloc-realloc) 一.单链表的实现与销毁 1.1 节点的定义 1.2 单链表的尾插 1.3 单链表的头插 1.4 单链表的尾删 1.5 单链表的头删 1…

二维数组中的查找

😀前言 在解决问题时,我们经常会遇到需要在二维数组中查找特定元素的情况。然而,如果直接使用暴力搜索,即遍历整个数组寻找目标元素,可能会导致时间复杂度较高,效率不高。然而,对于给定的二维数…

将Composite Collider 2D组件移除可解决Unity穿墙问题

将Composite Collider 2D组件移除可解决Unity穿墙问题

HTTP/UDP/TCP/IP网络协议

文章目录 计算机网络基础HTTP相关问题 UDPTCP连接管理(三次握手/四次挥手)TCP可靠传输(确认答应)超时重传滑动窗口流量控制拥塞控制延时应答捎带应答粘包问题其他 IP数据链路层MUT 网卡接收数据流程相关问题TCP会粘包、UDP永远不会粘包 学习博客 计算机网络基础 OSI模型定义了…

vue3 路由允许通过跳转访问,不允许通过空白页访问,同时通过路由跳转来的刷新不会丢失

背景说明 需要是这样的: 假设这个路由是/aa 它可以通过其它路由跳转进入 或 访问路由标签进入。如:通过路由/bb跳转进入到路由/aa:在路由/bb中写如下代码router.push({ path: /aa })不允许通过空白页进入。如 由路由/bb跳转到路由/aa后&am…

Oracle数据库imp文件导入失败提示:“不是有效的导出文件, 标头验证失败”解决方法

导入数据库时,直接提示不是有效的导出文件,标头验证失败 原因:这是因为导出的imp文件和你当前导入的数据库版本不一致造成的,例如:导出文件版本号12.0.1 导入数据库的版本号11.0.2,会报这个错误。 解决办法…

【Java EE】获取Cookie和Session

文章目录 🎍Cookie简介🍀理解Session🌳Cookie 和 Session 的区别🌲获取Cookie🌸传统获取Cookie🌸简洁获取Cookie 🌴获取Session🌸Session存储🌸Session读取🌻…

tsc --init 报错

运行 tsc --init 报错, 全局安装 ts 也不行 通过 npx tsc --init 就可以解决

创建大量栅格文件并分别写入像元数据:C++ GDAL代码实现

本文介绍基于C语言GDAL库,批量创建大量栅格遥感影像文件,并将数据批量写入其中的方法。 首先,我们来明确一下本文所需实现的需求。已知我们对大量遥感影像进行了批量读取与数据处理操作——具体过程可以参考文章C GDAL提取多时相遥感影像中像…

python开发poc,fofa爬虫批量化扫洞

学习使用python做到批量化的漏洞脚本 1.通过fofa搜索结果来采集脚本 2.批量化扫描漏洞 ---glassfish存在任意文件读取在默认48484端口,漏洞验证的poc为: "glassfish" && port"4848" && country"CN" http://loca…

渗透学习第一天:DR4G0N B4LL靶场复现

0x00 环境搭建 攻击机为kali Linux,IP为192.168.71.129 靶机IP地址目前不知道,但是是和kali同网段的 0x01 信息收集 由于不知道目标的IP地址,这里我采用了arp scan对本机的整个网段进行扫描 发现目标IP为192.168.71.130。对目标IP进行端…

新品攻略—小功率、小体积、高效率!LED驱动模块RSC6218A

瑞森半导体(REASUNOS)推出应用在5W-18W LED电源上的LED驱动模块RSC6218A。 LED驱动模块RSC6218A是一款LLC 谐振拓扑功率模块,带有半桥驱动的控制电路和功率转化器件,适用于 LED 恒流控制线路,电路工作频率可达200KHz。…

MATLAB绘采用低通滤波处理加噪方波信号

MATLAB绘采用低通滤波处理加噪方波信号 clc;close all;clear all;warning off;%清除变量 rand(seed, 100); randn(seed, 100); format long g;% MATLAB代码:绘制加噪方波并采用低通滤波后绘制图像 % 参数设置 Fs 1000; % 采样频率 T 1/Fs; …

“更大的焦虑,更大的想象力”:音视频厂商如何闯入AI时代?

从GPT3.5到GPT4.0,从Runway、Pika到Sora,当大模型的价值链不断升级,那些暂未爬到顶端的企业,还剩下多少‘生存空间’? 于音视频厂商而言,企业要解决的难题是,如何将技术与用户连接在一起。让大…

PPE-个人防护装备如何定义?为什么说PPE是劳动者的护身神器?

个人防护用品定义 PPE,即个人防护装备、个人防护用具或劳保用品,是劳动场所中不可或缺的重要组成部分。它们扮演着保护工人免受各种危害的关键角色。从安全帽到反光衣,再到防护手套和安全鞋,PPE覆盖了各个方面,为工人…