【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

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

BUUCTF(34)特殊的 BASE64

使用pycharm时,如果想把代码撤销到之前的状态可以用 Ctrl+z 如果不小心撤销多了,可以用 Ctrl+Shift+Z 还原, 别傻傻的重新敲了 BUUCTF在线评测 (buuoj.cn) 查看字符串,想到base64的变表 这里用的c++的标准程序库中的string,头文件是#include<string> 这是base64的加密函数 std::string

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

LabVIEW FIFO详解

在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式,包括目标范围内FIFO(Target-Scoped)、DMA FIFO以及点对点流(Peer-to-Peer)。 FIFO类型 **目标范围FIFO(Target-Sc

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓