4.Redis基础和数据结构

感谢秦疆老师的redis视频教程,更多了解哔哩哔哩搜索【狂神说Java】。

本文内容源于秦疆老师的redis视频教程。给狂神推荐,点赞吧!

基础知识

redis默认有16个数据库。

在这里插入图片描述
默认使用的是第0个数据库。

可以使用select进行切换

[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize #查看db大小
(integer) 0

在这里插入图片描述

  • 清除当前数据库 flushdb
  • 清空所有数据库 flushall
127.0.0.1:6379[3]> keys * #查看数据库的所有key
1) "name"
127.0.0.1:6379[3]> flushdb #清除当前数据库 flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379> flushall #清空所有数据库
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> 

思考:为什么redis端口号是6379?

6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。(粉丝效应)

更多了解见知乎:Redis 为什么要用 6379 作为默认端口?

Redis是单线程的

明白Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!

Redis 是C语言写的,官方提供的数据为 100000 +的QPS,完全不比同样是使用key-value 的Memecache差

Redis 为什么单线程还这么快?

1、误区1 :高性能的服务器一定是多线程的?
2、误区2 :多线程(CPU上下文会切换!)一定比单线程效率高

先去CPU>内存>硬盘的数据要有所了解!

核心:redis 是将所有的数据全部放在内存中的,所以说使用单线程去操作效率是最高的。多线程(CPU上下文会切换:耗时的操作),对于内存系统来说,如果没有上下文切换效率是最高的!多次读写都是在一个CPU内,这个就是最佳的方案!

五大数据类型

官方文档

在这里插入图片描述
中文文档翻译

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库缓存消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

后面使用的SpringBoot,Jedis,所有方法都是这些命令!

单点登录

Redis-Key

127.0.0.1:6379> keys *  #查看所有的key
(empty array)
127.0.0.1:6379> set name lq #set key
OK
127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name #判断当前的key是否存在
(integer) 1
127.0.0.1:6379> move age 1
(integer) 1
127.0.0.1:6379> exists name1 # 移除当前的key
(integer) 0
127.0.0.1:6379> expire name 10 # 设置key的过期时间 ,单位是秒
(integer) 1
127.0.0.1:6379> ttl name #查看当前key的剩余时间
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type name #查看当前key的一个类型
string

以后遇到不会的命令,可以在官网查看帮助文档!

在这里插入图片描述

String

90%的Java程序员使用redis只会String类型才怪!

#################################################
[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set key1 hello # 设置值
OK
127.0.0.1:6379> get key1 #获得值
"hello"
127.0.0.1:6379> keys * #获取所有值
1) "name"
2) "key1"
127.0.0.1:6379> exists key1 #判断某个key是否存在
(integer) 1
127.0.0.1:6379> append key1 ",word" #追加字符串,如果当前key不存在,就相当于 set key
(integer) 10
127.0.0.1:6379> get key1
"hello,word"
127.0.0.1:6379> strlen key1 #获取字符串的长度!
(integer) 10
127.0.0.1:6379> append key1 "!"
(integer) 11
127.0.0.1:6379> strlen key1
(integer) 11
127.0.0.1:6379> get key1
"hello,word!"

################################################


127.0.0.1:6379> set views 0 # 初始浏览量为0 
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增1 浏览量变为1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> incr views 
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views# 自减1 浏览量变为1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> incrby views 10 #设置步长,指定增量
(integer) 11
127.0.0.1:6379> incrby views 10
(integer) 21
127.0.0.1:6379> decrby views 5 #设置步长,指定减量
(integer) 16
127.0.0.1:6379> decrby views 5
(integer) 11

################################################
字符串范围 getrange
127.0.0.1:6379> get key1
"hello,word!"
127.0.0.1:6379> getrange key1 0 3 #截取字符串 [0,3]
"hell"
127.0.0.1:6379> get key1
"hello,word!"
127.0.0.1:6379> getrange key1 0 -1 #获取全部的字符串 和 get key 是一样的
"hello,word!"



#替换!
[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> keys *
1) "key"
2) "name"
3) "views"
4) "key1"
127.0.0.1:6379> set key2 test123
OK
127.0.0.1:6379> get key2
"test123"
127.0.0.1:6379> setrange key2 1 xx #替换指定位置开始的字符串!
(integer) 7
127.0.0.1:6379> get key2
"txxt123"



################################################
#setex(set with expire) #设置当前过期时间
#setnx(set if not exist) #不存在再设置 (在分步式锁中会常常使用!)

127.0.0.1:6379> setex key3 30 "hello" #设置key3的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) 25
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
2) "name"
3) "views"
4) "key2"
5) "key"
6) "key1"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "MongDB"  #如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"


################################################
mset
mget

127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> KEYS *
(empty array)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个原子的操作,要么一起成功,要么一起失败!
(integer) 0
127.0.0.1:6379> get v4
(nil)
127.0.0.1:6379> get k4
(nil)

#对象
set user:1 {name:zhang,age:3} #设置一个user:1 对象 值为json字符来保存一个对象!

[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> set user:1 {name:zhang,age:11}
OK
127.0.0.1:6379> get user:1
"{name:zhang,age:11}"


#这里的key是一个巧妙的设计, user:{id}:{filed},如此设计在redis中是完全OK的!

127.0.0.1:6379> mset user:2:name lq user:2:age 23
OK
127.0.0.1:6379> mget user:2:name user:2:age
1) "lq"
2) "23"
127.0.0.1:6379> 

################################################
getset #先get再set

127.0.0.1:6379> getset db redis #如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongdb #如果存在值,获取原来的值,并且设置新的值
"redis"
127.0.0.1:6379> get db
"mongdb"


数据结构是相同的!

String类似的使用场景:value除了是我们的字符串还可以是我们的数字

  • 计数器
  • 统计多单位的数量mget mset (浏览器 关注量 播放数 uid:9634343:follow 0 incr )
  • 粉丝数
  • 对象缓存存储!(设置过期时间)

List(列表)

基本的数据结构,列表

在这里插入图片描述
在redis里面,我们可以把list完成 栈 ,队列,阻塞队列!

所有的list命令都是以l开头,redis不区分大小写

##################################################

[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> lpush list one #将一个值或者多个值,插入到列表头部(左)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 #获取lsit中的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 #通过区间获取具体的值!
1) "three"
2) "two"
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> rpush list right #将一个值或者多个值,插入到列表的尾部(右)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> 


##################################################

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list #移出list的第一个元素
"three"
127.0.0.1:6379> rpop list #移出list的最后一个元素
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

##################################################
lindex

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1 #通过下标获取List中的某一个值
"one"
127.0.0.1:6379> lindex list 0
"two"
##################################################
llen

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> llen list #返回列表的长度
(integer) 3
##################################################
移除指定的值:
取关 uid 

lrem
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 three #移除list集合指定个数的value,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpush list three
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 3 three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"



##################################################
trim 修剪 : list 截断

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2 #通过下标截取指定的长度
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"

##################################################
rpoplpush #移除列表的最后一个元素,将他移动到新的列表中

127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
127.0.0.1:6379> rpoplpush mylist myotherlist #移除列表的最后一个元素,将他移动到新的列表中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1 #查看原来的列表
1) "hello1"
127.0.0.1:6379> lrange myotherlist 0 -1  #查看目标列表,确实存在移动改值
1) "hello2"

##################################################
lset 将列表中指定下标的值替换成另一个值,更新操作

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> exists list #判断这个列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item #如果不存在列表我们去更新就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list "hello"
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "hello"
127.0.0.1:6379> lset list 0 item #如果存在,更新当前下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 other #如果不存在,则会报错
(error) ERR index out of range

##################################################
linsert  before|after #讲某个具体的value插入到列中某个元素的前面或者后面

127.0.0.1:6379> keys * 
(empty array)
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "world"
(integer) 2
127.0.0.1:6379> linsert mylist before "world" "other"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert mylist after world new
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"


小结

  • 它实际是一个链表,before Node after ,left ,right都可以插入值
  • 如果Key不存在,创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在!
  • 在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点~

消息队列!消息队列(Lpush Rpop),栈(Lpusn Lpop)

Set(集合)

set中的值是不可重复的!

##################################################
127.0.0.1:6379> sadd myset "hello" #set集合中添加值
(integer) 1
127.0.0.1:6379> sadd myset "test"
(integer) 1
127.0.0.1:6379> sadd myset "admin"
(integer) 1
127.0.0.1:6379> smembers myset #查看指定set的所有值
1) "test"
2) "hello"
3) "admin"
127.0.0.1:6379>  sismember myset hello #判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) s0

##################################################
127.0.0.1:6379> scard myset #获取set集合中的内容元素个数!
(integer) 3

##################################################

127.0.0.1:6379> srem myset hello #移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> smembers myset
1) "test"
2) "admin"

##################################################
#set 无序不重复集合 抽随机 抽奖 srandmember
127.0.0.1:6379> SRANDMEMBER myset 2 #s随机抽选出指定个数的元素
1) "test"
2) "test3"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "test1"
2) "test3"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "test1"
2) "test"
127.0.0.1:6379> SRANDMEMBER myset 
"test2"
127.0.0.1:6379> SRANDMEMBER myset
"test"
127.0.0.1:6379> SMEMBERS myset #随机抽选一个元素
1) "test1"
2) "test2"
3) "test3"
4) "test"
5) "test4"
6) "admin"
##################################################
删除指定的key 随机删除key
127.0.0.1:6379> spop myset #随机删除一些set集合中的元素!
"admin"
127.0.0.1:6379> spop myset
"test1"
127.0.0.1:6379> SMEMBERS myset
1) "test2"
2) "test3"
3) "test"
4) "test4"
##################################################
将一个指定的值 移动到另一个set集合

127.0.0.1:6379> SMEMBERS myset
1) "test2"
2) "test3"
3) "test"
4) "test4"
127.0.0.1:6379> sadd myset2 mytest1
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "mytest1"
127.0.0.1:6379> smove myset myset2 test4
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "test2"
2) "test3"
3) "test"
127.0.0.1:6379> SMEMBERS myset2
1) "test4"
2) "mytest1"
##################################################
微博 ,B站,共同关注(并集)
数字集合类;
-差集
-交集
-并集

127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2 #差集
1) "b"
2) "a"
127.0.0.1:6379> sinter key1 key2 #交集 共同好友就可以这样实现
1) "c"
127.0.0.1:6379> sunion key1 key2 #并集 
1) "a"
2) "c"
3) "b"
4) "e"
5) "d"

微博 A用户 将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!

共同好友,共同爱好,二度好友,推荐好友!(六度分割理论

Hash(哈希)

Map集合,key-map ! 这个值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-value!

set myhash filed test

##################################################
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset myhash filed1 hello #set一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash filed1 #获取一个字段值
"hello"
127.0.0.1:6379> hmset myhash filed1 test filed2 #set多个的key-value world
OK
127.0.0.1:6379> hmget myhash filed1 filed2 #获取多个字段值
1) "test"
2) "world"
127.0.0.1:6379> hgetall myhash #获取全部的数据
1) "filed1"
2) "test"
3) "filed2"
4) "world"
127.0.0.1:6379> hdel myhash filed1 #删除hash指定的key字段!对应的value也就消失了!
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "filed2"
2) "world"
######################################################
hlen

127.0.0.1:6379> hlen myhash #获取hash表的字段数量
(integer) 1
######################################################
hexists

127.0.0.1:6379> hexists myhash filed1 #判断hash中的指定字段是否存在
(integer) 0
127.0.0.1:6379> hexists myhash filed2
(integer) 1

######################################################
#只获得所有的key		hkeys 
#只获得所有的value	hvals

127.0.0.1:6379> hkeys myhash #只获得所有的key		
1) "filed2"
127.0.0.1:6379> hvals myhash #只获得所有的value
1) "world"

######################################################
incr decr

127.0.0.1:6379> hset myhash count 3 #指定增量
(integer) 1
127.0.0.1:6379> hincrby myhash count -1
(integer) 2
127.0.0.1:6379> hincrby myhash count -1
(integer) 1
127.0.0.1:6379> hsetnx myhash filed3 hello #如果不存在则可以设置
(integer) 1
127.0.0.1:6379> hsetnx myhash filed3 world #如果存在则不能设置
(integer) 0
#################################################


#hash变更的数据 user name age ,尤其是用户信息之类的
127.0.0.1:6379> hset user:1 name li
(integer) 1
127.0.0.1:6379> hget user:1 name
"li"


hash变更的数据 user name age ,尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,String更适合字符串储存

Zset(有序集合)

在set的基础上,增加了一个值,set k1 v1 zset k1 score1 v1

##################################################
[root@izbp1a6mu5e8nzvi0x15cwz bin]# redis-cli -p 6379
127.0.0.1:6379> zadd myset 1 one #添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three #添加多个值
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"

##################################################
排序如何实现 最小值到最大值

127.0.0.1:6379> zadd salary 2500 xaioming #添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 5000 liutian
(integer) 1
127.0.0.1:6379> zadd  salary 300 shunchen
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf #显示全部的用户 从小到大!
1) "shunchen"
2) "xaioming"
3) "liutian"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf  withscores #显示全部用户并附带成绩
1) "shunchen"
2) "300"
3) "xaioming"
4) "2500"
5) "liutian"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores #显示工资小于2500的升序排列
1) "shunchen"
2) "300"
3) "xaioming"
4) "2500"
127.0.0.1:6379> ZREVRANGE salary 0 -1 #倒序排列 从大到小
1) "liutian"
2) "xaioming"



##################################################
#移除rem中的元素

127.0.0.1:6379> zrange salary 0 -1
1) "shunchen"
2) "xaioming"
3) "liutian"
127.0.0.1:6379> zrem salary shunchen #移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "xaioming"
2) "liutian"
127.0.0.1:6379> zcard salary #获取有序集合之间的个数
(integer) 2


##################################################

127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 2 world 3 test
(integer) 2
127.0.0.1:6379> zcount myset 1 3 #获取指定区间的成员数量
(integer) 6
127.0.0.1:6379> zcount myset 1 2
(integer) 4
127.0.0.1:6379> zrange myset 0 -1
1) "hello"
2) "one"
3) "two"
4) "world"
5) "test"
6) "three"


其余API,可查看官方文档

案例思路:

  • set 排序 存储班级成绩表 ,工资表排序!
  • 普通消息设置 为1;重要消息设置为 2, 带权重进行判断!
  • 排行版应用实现,取Top N测试!

三种特殊的数据类型

geospatial地理位置

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

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

参考城市经纬度查询、国内地区经度纬度查询工具:http://www.jsons.cn/lngcode/

只有六个命令:

在这里插入图片描述

参考中文文档:https://www.redis.net.cn/order/3685.html

参考导入方式:将ip对应城市数据导入redis并查询

geoadd

#geoadd 添加地理位置
#规则 : 两极无法直接添加 ,我们一般会下载城市数据,直接通过java程序一次性导入!

参考导入方式:将ip对应城市数据导入redis并查询https://blog.csdn.net/aen7046/article/details/102423228

127.0.0.1:6379> geoadd china:city 39.90 116.40 beijin
(error) ERR invalid longitude,latitude pair 39.900000,116.400000


#参数  key 值()
将给定的空间元素(纬度、经度、名字)添加到指定的键里面。 这些数据会以有序集合的形式被储存在键里面, 从而使得像 GEORADIUS 和 GEORADIUSBYMEMBER 这样的命令可以在之后通过位置查询取得这些元素。

GEOADD 命令以标准的 x,y 格式接受参数, 所以用户必须先输入经度, 然后再输入纬度。 GEOADD 能够记录的坐标是有限的: 非常接近两极的区域是无法被索引的。 精确的坐标限制由 EPSG:900913 / EPSG:3785 / OSGEO:41001 等坐标系统定义, 具体如下:

有效的经度介于 -180 度至 180 度之间。
有效的纬度介于 -85.05112878 度至 85.05112878 度之间。
当用户尝试输入一个超出范围的经度或者纬度时, GEOADD 命令将返回一个错误。

127.0.0.1:6379> geoadd china:city 114.08 22.54 shenzhen
(integer) 1
127.0.0.1:6379> geoadd china:city 115.89 28.67 nanchan
(integer) 1

geopos

获得当前定位:一定是个坐标值!

127.0.0.1:6379> geopos china:city shenzhen #获取指定的城市的精度和纬度
1) 1) "114.08000081777572632"
   2) "22.53999903789756587"
127.0.0.1:6379> geopos china:city shenzhen nanchan
1) 1) "114.08000081777572632"
   2) "22.53999903789756587"
2) 1) "115.88999837636947632"
   2) "28.66999910629679249"

geodist

两人之间的距离!

单位:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。
127.0.0.1:6379> geodist china:city shenzhen nanchan #查看深圳到 南昌的直线距离
"705535.9887"
127.0.0.1:6379> geodist china:city shenzhen nanchan km #查看深圳到 南昌的直线距离 km为单位
"705.5360"

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

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

获得指定数量的人 , 200

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


127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km #以110,30 这个经纬度为中心,寻找方圆1000km内的城市
1) "shenzhen"
2) "nanchan"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
(empty array)
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist #显示到中心距离的位置
1) 1) "shenzhen"
   2) "923.9364"
2) 1) "nanchan"
   2) "589.8814"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord #显示他人的定位信息
1) 1) "shenzhen"
   2) 1) "114.08000081777572632"
      2) "22.53999903789756587"
2) 1) "nanchan"
   2) 1) "115.88999837636947632"
      2) "28.66999910629679249"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist withcoord count 2 #筛选出指定的结果
1) 1) "nanchan"
   2) "589.8814"
   3) 1) "115.88999837636947632"
      2) "28.66999910629679249"
2) 1) "shenzhen"
   2) "923.9364"
   3) 1) "114.08000081777572632"
      2) "22.53999903789756587"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist withcoord count 1
1) 1) "nanchan"
   2) "589.8814"
   3) 1) "115.88999837636947632"
      2) "28.66999910629679249"

georadiusbymember 用于城市与城市 小区与小区之间的定位

#找出位于指定元素周围的其他元素!

127.0.0.1:6379> GEORADIUSBYMEMBER china:city shenzhen 1000 km
1) "shenzhen"
2) "nanchan"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city nanchan 600 km
1) "nanchan"

geohash 命令 返回一个或者多个位置元素的geohash表示

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

#将二维的经纬度转化为一维的字符串,如果两个字符串越接近,那么表示距离越近
127.0.0.1:6379> geohash china:city shenzhen nanchan
1) "ws105zq9080"
2) "wt47j5hwbe0"

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

127.0.0.1:6379> ZADD china:city 0 -1
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1 #查看地图中全部元素
1) "-1"
2) "shenzhen"
3) "nanchan"
127.0.0.1:6379> zrem china:city -1
(integer) 1
127.0.0.1:6379> zrem china:city nanchan #移除指定元素
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "shenzhen"

Hyperloglog

什么是基数?

A {1,3,5,7,8,7}

B { 1,3,5,7,8}

基数(不重复的元素) = 5 ,可以接受误差!

简介

Redis2.8.9版本就更新了Hyperloglog数据结构!

Redis Hyperloglog 基数统计的算法!

优点:占用的内存是固定的,2^64个不同的元素的技术,只需要废12KB内存!如果要从内存角度来比较的话 Hyperloglog首选!

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

传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!

这个方式如果保存大量的用户的id,就会比较麻烦!我们的目的是计数,而不是保存用户id;

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

测试使用

#

127.0.0.1:6379> pfadd mykey a b c d e f g h i j k #创建第一组元素 mykey 
(integer) 1
127.0.0.1:6379> pfcount mykey #统计 mykey 元素的基数数量
(integer) 11
127.0.0.1:6379> pfadd mykey2 i j k z x a b b m n   #创建第二组元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 9
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 #合并两组 mykey mykey2 => mykey3 并集
OK
127.0.0.1:6379> pfcount mykey3 #看并集的数量
(integer) 15

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

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

Bitmaps

位存储

  • 统计疫情感染人数: 0 1 0 1 0 0 0 (感染为1 未感染为0)
  • 统计用户信息,活跃,不活跃!登录,未登录!打卡,365打卡! 两个状态的,都可以使用Bitmaps!
  • Bitmaps位图,数据结构!都是操作二进制来进行记录,就只有0和1两种状态
  • 365天 = 365bit 1字节 = 8bit 46个字节左右!

测试

在这里插入图片描述

  • 使用Bitmap来记录周一到周日的打卡!
  • 周一 : 1 周二: 0
(integer) 15
127.0.0.1:6379> setbit sign 0 1 
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
  • 查看某天是否打卡
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 1
(integer) 0

  • 统计操作,统计打卡的天数
127.0.0.1:6379> bitcount sign #统计这周打卡的记录,就可以看到是否有全勤!
(integer) 3
posted @ 2020-05-16 15:45  我有满天星辰  阅读(5)  评论(0编辑  收藏  举报