七天玩转Redis | Day3Redis地理位置基数统计位图场景使用详解

Posted 灰小猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七天玩转Redis | Day3Redis地理位置基数统计位图场景使用详解相关的知识,希望对你有一定的参考价值。

号外号外🎉🎉🎉:小猿和CSDN联合推出的“七天玩转Redis,打卡还能领周边”活动开始啦!点击查看👉🏻报名及活动细则👈🏻,轻轻松松和小伙伴们一起拿奖励吧!

PS:零基础也能入门Redis哟,快去一起参与拿周边吧!

博主简介👨🏼‍⚕️:国内某一线互联网公司Java工程师👨🏼‍💻,业余自媒体创作者💻,CSDN博客专家🏆,Java领域优质创作者📕,华为云享专家🥇,华为HDZ核心成员👨‍💼,曾发表并出版ISEAE信息科学国际论文,全网累计发表技术博客60余万📒,公众号【码猿编程日记】作者,坚信每一次敲动键盘都能让生活变得更智能,世界变得更有趣!

课前答疑:很多小伙伴问我零基础或者根本没有使用过Redis,可以学习嘛?当然是可以的!充分考虑到小伙伴们的学习程度有所不同,所以本次课程的所有操作都是在Windows环境下进行的,不会依赖太多的环境配置,且上手容易。已经学习过Redis的小伙伴们同样可以再学习一遍,温故而知新,还能拿CSDN定制周边!何乐而不为呢😀

今日学习内容

在上一篇的文章中我们讲解了在Redis中五大数据类型的基本使用,但是在Redis中其实还有三种非常实用的特殊数据类型,分别是Gaospatial地理位置、Hyperloglog基数统计、Bitmap位图场景,这三种特殊数据类型主要是对应了三种不同的使用场景。

所以我们今天这篇文章主要来和大家讲解一下这三种特殊数据类型的基本命令以及使用场景,保证你学习完之后颇有收获!!!

(1)Gaospatial地理位置

百度地图、高德地图这些地图软件大家应该都用过吧?输入两个位置,我们就可以得到两个位置之间的距离。或者你想要查询你附近500米以内的超市,那么你直接点击范围就可以。还有我们QQ、微信、玩游戏的时候的附近的人的查询你都可以查询得到。

而这些操作,在Redis的Gaospatial地理位置中都可以实现!

首先在课程开始之前先给大家推荐一个查询全国城市经纬度的网站,下面的学习中需要查询某个城市经纬度的话可以直接来这里查询:

城市经纬度查询-国内城市经度纬度在线查询工具http://www.jsons.cn/lngcode/

添加一个或多个地理位置的坐标

在地图中,如果我们想要查询一个位置,那么其实都是依据这个位置的坐标来实现的,所以在查询之前,一定是需要先将这个坐标输入的对吧,Redis的Gaospatial中添加地理位置坐标的命令是GEOADD,格式如下:

GEOADD key longitude latitude member [longitude latitude member ...]

  • key为该地理位置的索引
  • longitude表示该位置的经度
  • latitude表示该位置的纬度
  • member表示地名
  • [longitude latitude member ...]表示可以重复添加,中间以空格分隔

为了方便下面的命令的使用,建议大家在这一步多输入几个城市的经纬度,

比如我们查询深圳的经纬度为:114.085947(经度),22.547(纬度),

并且深圳是中国的城市,那么我们可以定义深圳的索引key是“china:city”,longitude是“114.08”,latitude是“22.54”,member是“shenzhen”,输入的命令就是这样的:

127.0.0.1:6379> GEOADD china:city 114.08 22.54 shenzhen
(integer) 1

注意:Gaospatial地理位置中,多个城市可以使用同一个key,比如“shenzhen”和“xian”的key都可以是“china:city”,我们在查询的时候可以通过索引+地名的形式查询,就像我们上面讲的Hash数据类型是一样的,

现在多输入几个城市:

127.0.0.1:6379> GEOADD china:city 114.08 22.54 shenzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 116.10 39.90 beijing
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.66 34.75 zhengzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 112.54 37.85 taiyuan
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.28 23.12 guangzhou
(integer) 1
127.0.0.1:6379>  GEOADD china:city 120.15 30.28 hangzhou 118.76 32.04 nanjing
(integer) 2

注意在输入经纬度的时候,数据是可以任意保留小数位的,而且现在虽然是一个一个写入,但是在开发的实际操作中,我们可以通过读取数据库直接写入。

查询一个或多个地理位置坐标

上面我们已经插入了很多条地理位置的数据,现在我们可以通过GEOPOS命令来获取指定地理位置的坐标,格式如下:

GEOPOS key member [member ...]

  • key表示输入时该地理位置的索引
  • member表示地理位置的名称,可以输入多个中间以空格分开

如我们要查询郑州、北京和长沙的地理坐标,(但是长沙的不存在,则返回null)

127.0.0.1:6379> GEOPOS china:city zhengzhou
1) 1) "113.65999907255172729"
   2) "34.74999926510690784"
127.0.0.1:6379> GEOPOS china:city beijing changsha
1) 1) "116.09999924898147583"
   2) "39.90000009167092543"
2) (nil)

查询两地之间的距离

在地图中我们经常会查询两个地方之间的距离,或者在微信中实时共享两个人的位置坐标,这个时候都是需要查询两个地方的距离来实现的,在Redis中查询两个地方距离的命令是:

GEODIST key member1 member2 [unit]

  • key为要查询的两个地理位置的索引,注意两个地理位置需要使用同一个索引,
  • member1为第一个位置名称
  • member2为第二个位置名称
  • [unit]为显示的单位,可以是m(米,默认)、km(千米)、ft(英尺)、mi(英里)

如我们查询郑州到杭州的直线距离,以米为单位,

127.0.0.1:6379> GEODIST china:city zhengzhou hangzhou
"785609.9719"
127.0.0.1:6379> GEODIST china:city zhengzhou hangzhou m
"785609.9719"

再查询深圳到北京的直线距离:

127.0.0.1:6379> GEODIST china:city shenzhen beijing km
"1940.2709"

查询到的结果是1940.2709km,我们百度验证一下:

查询到的结果稍微有一点误差,但是可以接受,产生误差的原因可能是输入的经纬度的精度问题,或者是百度和Redis定位的市中心的位置不一样都有可能。

以坐标为中心来范围搜索地理位置

我们平常都会使用到附近的人功能,或者以自己为中心搜索附近,Redis中可以使用命令GEORADIUS来指定附近多少米以内的地理位置的查询。

 GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

  • key为要查询的地理位置的索引
  • longitude为该地理位置的经度
  • latitude为该地理位置的纬度
  • radius表示要查询的半径
  • m|km|ft|mi表示单位
  • [WITHCOORD]可选,表示是否输出经纬度
  • [WITHDIST]可选,表示是否输出距离
  • [WITHHASH]可选,表示是否输出哈希值
  • [COUNT count]可选,表示输出几个数据
  • [ASC|DESC]可选,表示按照距离升序还是降序排列,ASC升序,DESC降序

比如我们查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1000 km
1) "shenzhen"
2) "guangzhou"

查询到的结果是深圳和广州,注意:只有我们输入的坐标才会被查询出来,没有输入的不会查询出来!

下面我们多看几个实例:

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出地理位置的坐标:

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出距离:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km WITHCOORD
1) 1) "shenzhen"
   2) 1) "114.08000081777572632"
      2) "22.53999903789756587"
2) 1) "guangzhou"
   2) 1) "113.27999979257583618"
      2) "23.1199990030198208"
3) 1) "hangzhou"
   2) 1) "120.15000075101852417"
      2) "30.2800007575645509"
4) 1) "zhengzhou"
   2) 1) "113.65999907255172729"
      2) "34.74999926510690784"
5) 1) "nanjing"
   2) 1) "118.75999957323074341"
      2) "32.03999960287850968"

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,同时输出距离:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km WITHDIST
1) 1) "shenzhen"
   2) "3.8011"
2) 1) "guangzhou"
   2) "103.3692"
3) 1) "hangzhou"
   2) "1055.1042"
4) 1) "zhengzhou"
   2) "1360.8264"
5) 1) "nanjing"
   2) "1156.3230"

查询深圳市福田区(114.05571,22.52245)半径1000km之内的城市,但只输出两个:

127.0.0.1:6379> GEORADIUS china:city 114.05 22.52 1500 km COUNT 2
1) "shenzhen"
2) "guangzhou"

以位置为中心来范围搜索地理位置

上面我们是以坐标的形式来进行范围搜索的,还有一种方式是以位置为中心进行搜索,这种的可以用于输入一个确定的地理位置进行范围搜索,这个命令和上面利用坐标进行范围搜索的使用方法基本一样,命令格式如下:

 GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

  • key为要查询的地理位置的索引
  • member为要作为中心点的地理位置
  • radius表示要查询的半径
  • m|km|ft|mi表示单位
  • [WITHCOORD]可选,表示是否输出经纬度
  • [WITHDIST]可选,表示是否输出距离
  • [WITHHASH]可选,表示是否输出哈希值
  • [COUNT count]可选,表示输出几个数据
  • [ASC|DESC]可选,表示按照距离升序还是降序排列,ASC升序,DESC降序

如我们查询以太原为中心,800km以内的城市:

127.0.0.1:6379> GEORADIUSBYMEMBER china:city taiyuan 800 km
1) "zhengzhou"
2) "taiyuan"
3) "beijing"

(2)Hyperloglog基数统计

Redis中的Hyperloglog主要是用来进行基数统计,很多小伙伴对于基数这个概念可能还不是很理解,什么是基数呢?

基数计算(cardinality counting)指的是统计一批数据中抛去重复元素后数据的个数

举个例子来说一下:

比如我们现在定义两个数字集合h1和h2

h1=1,3,5,7,9,7

h2=3,4,6,8,9,5

那么h1中抛去重复后得到的数据集合是1,3,5,7,9,所以h1的基数就是5,h2中跑去重复的元素后得到的集合是3,4,6,8,9,5,所以h2是的基数就是6,

那么基数统计一般用于什么情况下呢?比如我们一个人访问一次网站,就用一个数来记录,但是一个人可能会多次访问这个网站,那么如果想要知道多少人访问了网站,就需要去掉重复的数据。

使用基数统计的优势就是内存是固定的,使用内存非常小,可以减轻内存的使用,提升查询的效率!

创建一组数据

在进行基数统计之前肯定是要有数据源的,在Hyperloglog中可以通过PFADD命令创建数据

格式如下:

PFADD key element [element ...]

  • key为数据集的索引
  • element为数据集中的数据,可以输入多个,中间以空格分隔

例如我们输入索引为“mynum1”,数据为a,b,c,d,e,f,g的数据集,索引为“mynum2”,数据为f,g,h,i,j,k,l,m的数据集,索引为“mynum3”,数据为n,o,p,q,n的数据集.

127.0.0.1:6379> PFADD mynum1 a b c d e f g
(integer) 1
127.0.0.1:6379> PFADD mynum2 f g h i j k l m
(integer) 1
127.0.0.1:6379> PFADD mynum3 n o p q n
(integer) 1

统计数据集的基数数量

该命令就可以统计一个数据集的基数是多少,命令格式如下:

PFCOUNT key [key ...]

  • key为要查询的数据集的索引,可以输入多个,以空格分开

比如我们查询“mynum1”,“mynum1”中的七个元素都不重复,那么基数是7。查询“mynum3”,“mynum3”中的n重复,那么基数是4

127.0.0.1:6379> PFCOUNT mynum3
(integer) 4
127.0.0.1:6379> PFCOUNT mynum1
(integer) 7

合并数据集

合并数据集是可以将一个或多个数据集求并集,命令格式如下:

PFMERGE destkey sourcekey [sourcekey ...]

  • destkey为要合并到的数据集的名称
  • sourcekey为要合并的数据集的索引,可以存在多个,中间以空格分隔

比如我们将“mynum1”和“mynum2”合并并集为“mynum4”,再求“mynum4”的基数,得到13,是因为其中的f和g重复。

127.0.0.1:6379> PFMERGE mynum4 mynum1 mynum2
OK
127.0.0.1:6379> PFCOUNT mynum4
(integer) 13

(3)Bitmap位图场景

在Redis中的Bitmap位图是通过操作二进制位来实现的,在其中存储的数据要么是0,要么是1,比如下面这个0,1,1,0,0,0,0。而且位图中的每一个数据都是有唯一的一个下标对应的,和我们学习的数组类似。

那么位图有哪些使用场景呢?

比如我们想要统计CSDN用户是否活跃,假设CSDN有一亿用户,那么我们就将这一亿个用户的状态都表示为0,如果用户登录就表示活跃,那么我们就将该用户对应的数据置为1,但其实在Redis中一亿个0或者1的数据量是非常小的。

或者说用户登录,如果登录就用1表示,未登录就用0表示;公司打卡,打卡就用1表示,当天未打卡就用0表示。

我们以一周打卡的例子来讲解Bitmap位图的使用,

输入位图数据集

在Redis中给一个Bitmap输入数据的命令是SETBIT,格式如下:

SETBIT key offset value

  • key为该数据集的索引
  • offset为要输入的数据的下标
  • value为要输入的数据,0或1

如我们输入某个员工一周的打卡记录,数据集的索引是“mybit1”,注意数据集的下标是从0开始的。

127.0.0.1:6379> SETBIT mybit1 0 0    #下标为0表示第一天
(integer) 0
127.0.0.1:6379> SETBIT mybit1 1 1    #下标为1表示第二天
(integer) 0
127.0.0.1:6379> SETBIT mybit1 2 0    #下标为2表示第三天
(integer) 0
127.0.0.1:6379> SETBIT mybit1 3 0
(integer) 0
127.0.0.1:6379> SETBIT mybit1 4 1
(integer) 0
127.0.0.1:6379> SETBIT mybit1 5 1
(integer) 0
127.0.0.1:6379> SETBIT mybit1 6 0
(integer) 0

统计“1”的个数

如果我们想知道整个数据集中1的个数,也就是例子中打卡的天数,那么可以使用BITCOUNT命令,格式如下:

BITCOUNT key [start end]

  • key表示位图数据集的索引
  • [start end]表示开始和结束的下标,默认不写就是统计数据集中所有数据

如我们要查询该用户这一周打卡的天数,

127.0.0.1:6379> BITCOUNT mybit1
(integer) 3

注意啦,我们上面实验的这些数据现在虽然都是一个命令一个命令的输入的,但是在开发中这些都是可以通过Java类和方法批量写入的!

今日总结

今天的学习内容主要就是Redis中的三种特殊数据类型Gaospatial地理位置、Hyperloglog基数统计、Bitmap位图场景。这三种的基本命令使用都是需要了解知道的,虽然说他们的使用可能没有String类型那么多,但是在特殊场景下,它们的使用效率绝对比String类型高得多。

最后别忘记今天的总结打卡哟!【点击跳转社区打卡

在学习中存在任何问题的,大家都可以添加我的微信huixiaoyuan1030,(因为微信群二维码有效期只有七天😝),加入我们的“打卡答疑交流群”一起抱团、一起进步!

点击下方卡片可以找到我的微信二维码👇🏻👇🏻👇🏻

以上是关于七天玩转Redis | Day3Redis地理位置基数统计位图场景使用详解的主要内容,如果未能解决你的问题,请参考以下文章

七天玩转Redis | Day3Redis位图和GEO介绍与使用

七天玩转Redis | Day3 Redis地理位置基数统计位图场景使用详解

七天玩转Redis | Day3 Redis地理位置基数统计位图场景使用详解

七天玩转Redis | Day3 Redis地理位置基数统计位图场景使用详解

七天玩转Redis | Day4 Redis事务操作

七天玩转Redis | Day4Redis事务操作