【Redis】4、详解三种特殊数据类型 Geospatial、Hyperloglog、Bitmap

本文主要是介绍【Redis】4、详解三种特殊数据类型 Geospatial、Hyperloglog、Bitmap,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这三种特殊数据类型其实不是一个新的类型;底层还是五大类型中的一种;如:Zset、String

1、Geospatial 地理位置

geo:地理位置 spatial: [ˈspeɪʃl] 空间的

朋友的定位,附近的人,打车距离计算?

Redis 的 Geo 在Redis3.2 版本就推出了! 这个功能可以推算地理位置的信息,两地之间的距离,方圆
几里的人!

可以查询一些测试数据:http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/

在这里插入图片描述

官方文档:Redis命令中心 GEO

1)添加地理位置

  • geoadd key [NX|XX] [CH] longitude latitude member [longitude latitude member ...] 添加一个或多个位置的经度、纬度;先经度,后纬度

规则

  • 有效的经度从 -180 度到 180
  • 有效的纬度从 -85.05112878 度到 85.05112878

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

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

# 添加北京经纬度
127.0.0.1:6379> geoadd china:city 116.405285 39.904989 beijing
(integer) 1# 查看key
127.0.0.1:6379> keys *
1) "china:city"# key类型:zset
127.0.0.1:6379> type china:city
zset# 添加上海、广州、重庆
127.0.0.1:6379> geoadd china:city 121.47264 31.231706 shanghai 113.28063 23.125178 guangzhou 106.504962 29.533155 chongqing
(integer) 3# 查询全部
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "guangzhou"
3) "shanghai"
4) "beijing"

2)获取经纬度

  • geopos key member [member ...] 获取一个或多个位置的经纬度
127.0.0.1:6379> geopos china:city chongqing guangzhou
1) 1) "106.50495976209640503"2) "29.53315530684997015"
2) 1) "113.28062742948532104"2) "23.12517743834835215"

3)获取两地间的距离

  • geodist key member1 member2 [m|km|ft|mi] 获取两个位置成员间的距离

单位

  • m 表示单位为米(默认)
  • km 表示单位为千米
  • mi 表示单位为英里
  • ft 表示单位为英尺
# 北京、上海间的距离
127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.5978"
# 广州、重庆间的距义
127.0.0.1:6379> geodist china:city guangzhou chongqing
"981476.5000"

4)找出特定坐标范围内的其它元素

  • georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] 获取特定位置为中心,radius为半径的范围的其它位置
    • longitude latitude 中心坐标
    • radius m|km|ft|mi 半径及单位;中间有空格
    • withcoord 将位置元素的经度和纬度也一并返回
    • withdist 与中心之间的距离也一并返回
    • withhash 位置哈希值一并返回
    • count 返回元素的数量

我附近的人? (获得所有附近的人的地址,定位!)通过半径来查询!

获得指定数量的人,200

所有数据应该都录入:china:city ,才会让结果更加请求!

# 找出距离位置(100,30)方圆500km的其它城市
127.0.0.1:6379> georadius china:city 100 30 500 km
(empty array)# 找出距离位置(100,30)方圆1000km的其它城市,包含经纬度、距离、哈希值
127.0.0.1:6379> georadius china:city 100 30 1000 km withcoord withdist withhash
1) 1) "chongqing"2) "630.1140"3) (integer) 40260421178873714) 1) "106.50495976209640503"2) "29.53315530684997015"

5)找出特定成员范围内的其它元素

  • georadiusbymember key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] 找出距离member成员,方圆radius范围内的其它成员
127.0.0.1:6379> georadiusbymember china:city beijing 100 km
1) "beijing"
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
127.0.0.1:6379> georadiusbymember china:city beijing 2000 km
1) "chongqing"
2) "guangzhou"
3) "shanghai"
4) "beijing"127.0.0.1:6379> georadiusbymember china:city beijing 2000 km withcoord withdist withhash
1) 1) "chongqing"2) "1464.2210"3) (integer) 40260421178873714) 1) "106.50495976209640503"2) "29.53315530684997015"
2) 1) "guangzhou"2) "1889.3707"3) (integer) 40465337640664754) 1) "113.28062742948532104"2) "23.12517743834835215"
3) 1) "shanghai"2) "1067.5978"3) (integer) 40548034648170624) 1) "121.47264093160629272"2) "31.23170490709807012"
4) 1) "beijing"2) "0.0000"3) (integer) 40698853706710104) 1) "116.40528291463851929"2) "39.9049884229125027"

6)返回位置的哈希字符串

  • geohash key member [member ...] 返回一个或多个位置元素的哈希字符串(11个字符)
# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近!
127.0.0.1:6379> geohash china:city beijing chongqing
1) "wx4g0b7xrt0"
2) "wm78p86e170"

7)底层原理

GEO 底层的实现原理其实就是 Zset!可以使用Zset命令来操作geo!

127.0.0.1:6379> keys *
1) "china:city"
# key类型zset
127.0.0.1:6379> type china:city
zset# 查看所有
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "guangzhou"
3) "shanghai"
4) "beijing"# 删除
127.0.0.1:6379> zrem china:city chongqing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "guangzhou"
2) "shanghai"
3) "beijing"

2、Hyperloglog

1)介绍

走近源码:神奇的HyperLogLog - 知乎 (zhihu.com)

2)应用场景

  • 统计注册 IP 数
  • 统计每日访问 IP 数
  • 统计页面实时 UV 数
  • 统计在线用户数
  • 统计用户每天搜索不同词条的个数

网页的访问量 UV (一个人访问一个网站多次,但是还是算作一个人!)

传统的方式,set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断!这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;

使用HyperLogLog非常合适;

HyperLogLog有0.81% 错误率! 统计UV任务,可以忽略不计的!

如果允许容错,那么一定可以使用 Hyperloglog !

如果不允许容错,就使用 set 或者自己的数据类型即可!

3)添加 pfadd

  • pfadd key element [element ...] 向key中添加一个或多个元素
# 向mykey1中添加v1、v2、v3
127.0.0.1:6379> pfadd mykey1 v1 v2 v3
(integer) 1# key:mykey1
127.0.0.1:6379> keys *
1) "mykey1"# key的类型 string
127.0.0.1:6379> type mykey1
string# 元素数量 (数据量大时有误差)
127.0.0.1:6379> pfcount mykey1
(integer) 3# 字符串的值(无法查看mykey1中的具体元素)
127.0.0.1:6379> getrange mykey1 0 -1
"HYLL\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00G\x1f\x80o4\x88@P\x8cIV"

4)数量 pfcount

  • pfcount key [key ...] 获取一个或多个key中不重复元素的总数量
# 向mykey2中添加v10 v11 v12
127.0.0.1:6379> pfadd mykey2 v10 v11 v12
(integer) 1# mykey1中元素数量
127.0.0.1:6379> pfcount mykey1
(integer) 3 # 分别为v1 v2 v3
# 再向mykey1中添加v11
127.0.0.1:6379> pfadd mykey1 v11
(integer) 1
# mykey1中元素数量
127.0.0.1:6379> pfcount mykey1
(integer) 4 # 分别为v1 v2 v3 v11# mykey1和mykey2中元素的总数量(不重复元素)
127.0.0.1:6379> pfcount mykey1 mykey2
(integer) 6

5)合并 pfmerge

  • pfmerge destkey sourcekey [sourcekey ...] 把一个或多个sourcekey合并到一个目标destkey中
127.0.0.1:6379> keys *
1) "mykey2"
2) "mykey1"# 把mykey1、mykey2合并到mykey3
127.0.0.1:6379> pfmerge mykey3 mykey1 mykey2
OK127.0.0.1:6379> keys *
1) "mykey3"
2) "mykey2"
3) "mykey1"# mykey3中不重复元素的个数;效果等同于pfcount mykey1 mykey2
127.0.0.1:6379> pfcount mykey3
(integer) 6

3、Bitmap

原文链接:Redis 中 BitMap 的使用场景

1)概念

BitMap 原本的含义是用一个比特位来映射某个元素的状态。由于一个比特位只能表示 01 两种状态,所以 BitMap 能映射的状态有限,但是使用比特位的优势是能大量的节省内存空间

在 Redis 中,可以把 Bitmap 想象成一个以比特位为单位的数组,数组的每个单元只能存储0和1,数组的下标在 Bitmap 中叫做偏移量

在这里插入图片描述

需要注意的是:BitMap 在 Redis 中并不是一个新的数据类型,其底层是 Redis 的 String 类型。

2)相关命令

(1)设置值 setbit

# 设置值,其中value只能是 0 和 1
setbit key offset value

(2)获取值 getbit

# 获取值
getbit key offset

(3)获取1的个数 bitcount

# 获取指定范围内值为 1 的个数
# start 和 end 以字节为单位
bitcount key start end

(4)BitMap间运算 bitop

# BitMap间的运算
# operations 位移操作符,枚举值AND 与运算 &OR 或运算 |XOR 异或 ^NOT 取反 ~
# result 计算的结果,会存储在该key中
# key1 … keyn 参与运算的key,可以有多个,空格分割,not运算只能一个key
# 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。返回值是保存到 destkey 的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。
bitop [operations] [result] [key1] [keyn…]

(5)值第一次出现的位置 bitpos

# 返回指定key中第一次出现指定value(0/1)的位置
bitpos [key] [value]

3)占用空间

在弄清 BitMap 到底占用多大的空间之前,我们再来重申下:Redis 其实只支持 5 种数据类型,并没有 BitMap 这种类型,BitMap 底层是基于 Redis 的字符串类型实现的。

我们通过下面的命令来看下 BitMap 占用的空间大小:

# 首先将偏移量是0的位置设为1;其中 csx:key:1 表示一个key
127.0.0.1:6379> setbit csx:key:1 0 1
(integer) 0
# 通过STRLEN命令,我们可以看到字符串的长度是1
127.0.0.1:6379> STRLEN csx:key:1
(integer) 1
# 将偏移量是1的位置设置为1
127.0.0.1:6379> setbit csx:key:1 1 1
(integer) 0
# 此时字符串的长度还是为1,因为一个字符串有8个比特位,不需要再开辟新的内存空间
127.0.0.1:6379> STRLEN csx:key:1
(integer) 1
# 将偏移量是8的位置设置成1
127.0.0.1:6379> setbit csx:key:1 8 1
(integer) 0
# 此时字符串的长度编程2,因为一个字节存不下9个比特位,需要再开辟一个字节的空间
127.0.0.1:6379> STRLEN csx:key:1
(integer) 2

通过上面的实验我们可以看出,BitMap 占用的空间,就是底层字符串占用的空间。假如 BitMap 偏移量的最大值是 OFFSET_MAX,那么它底层占用的空间就是:

(OFFSET_MAX/8)+1 = 占用字节数

因为字符串内存只能以字节分配,所以上面的单位是字节。

但是需要注意,Redis 中字符串的最大长度是 512M,所以 BitMap 的 offset 值也是有上限的,其最大值是:

8 * 1024 * 1024 * 512  =  2^32

由于 C语言中字符串的末尾都要存储一位分隔符,所以实际上 BitMap 的 offset 值上限是:

(8 * 1024 * 1024 * 512) -1  =  2^32 - 1

4)使用场景

1. 用户签到

很多网站都提供了签到功能,并且需要展示最近一个月的签到情况,这种情况可以使用 BitMap 来实现。
根据日期 offset = (今天是一年中的第几天) % (今年的天数),key = 年份:用户id

如果需要将用户的详细签到信息入库的话,可以考虑使用一个一步线程来完成。

2. 统计活跃用户(用户登陆情况)

使用日期作为 key,然后用户 id 为 offset,如果当日活跃过就设置为1。具体怎么样才算活跃这个标准大家可以自己指定。

假如 20201009 活跃用户情况是: [1,0,1,1,0]
20201010 活跃用户情况是 :[ 1,1,0,1,0 ]

统计连续两天活跃的用户总数:

# 合并两天的key
bitop and dest1 20201009 20201010 
# dest1 中值为1的offset,就是连续两天活跃用户的ID
bitcount dest1

统计20201009 ~ 20201010 活跃过的用户:

# 或运算(并集)
bitop or dest2 20201009 20201010 

3. 统计用户是否在线

如果需要提供一个查询当前用户是否在线的接口,也可以考虑使用 BitMap 。即节约空间效率又高,只需要一个 key,然后用户 id 为 offset,如果在线就设置为 1,不在线就设置为 0。

4. 实现布隆过滤器

这篇关于【Redis】4、详解三种特殊数据类型 Geospatial、Hyperloglog、Bitmap的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/345056

相关文章

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

C#读写文本文件的多种方式详解

《C#读写文本文件的多种方式详解》这篇文章主要为大家详细介绍了C#中各种常用的文件读写方式,包括文本文件,二进制文件、CSV文件、JSON文件等,有需要的小伙伴可以参考一下... 目录一、文本文件读写1. 使用 File 类的静态方法2. 使用 StreamReader 和 StreamWriter二、二进

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri