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) 与范围查询, bitmaps, hyperloglogs 和地理空间(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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?