跳至主要內容

Redis数据类型

晨光-向大约 21 分钟RedisRedis数据库非关系型数据库缓存

Redis数据类型

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

1. 五大数据类型

Redis-Key

127.0.0.1:6379> keys * # 查看所有key
(empty list or set)
127.0.0.1:6379> set name chggx # 设置key
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name # 查看key
"chggx"
127.0.0.1:6379> set age 3
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> exists name # 判断当前的key是否存在
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 1 # 移除当前的key 1: 数据库号(16个数据库)
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name chenguangxiang
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"chenguangxiang"
127.0.0.1:6379> expire name 10 # 设置key的过期时间,单位是秒
(integer) 1
127.0.0.1:6379> ttl name # 查看当前key的剩余时间
(integer) 6
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> type age # 查看当前key的类型
string

keys * : 查看所有key

set name XX : 设置key

get name : 查看key

exists name : 判断当前的key是否存在

move name 1 : 移除当前的key 1: 数据库号(16个数据库)

expire name 10 : 设置key的过期时间,单位是秒

ttl name : 查看当前key的剩余时间

type age : 查看当前key的类型

注意: name为这里的key

String(字符串)open in new window

============================== 字符串拼接 ======================================
# append: 拼接字符串,如果当前key不存在,就相当于setkey

127.0.0.1:6379> set key1 v1 # 设置值
OK
127.0.0.1:6379> get key1 # 获取值
"v1"
127.0.0.1:6379> exists key1 # 判断某一个key是否存在
(integer) 1
127.0.0.1:6379> keys * # 获取所有key
1) "key1"
127.0.0.1:6379> append key1 "hello" # 追加字符串,如果当前key不存在,就相当于setkey
(integer) 7
127.0.0.1:6379> get key1 
"v1hello"
127.0.0.1:6379> strlen key1 # 获取字符串的长度!
(integer) 7
127.0.0.1:6379> append key1 ",chggx"
(integer) 13
127.0.0.1:6379> get key1
"v1hello,chggx"
===============================================================================

=============================== 自增/自减 ======================================
# 自增/自减 i++/i--
# incr: 自增
# decr: 自减
# 步长 i+=
# incrby: 设置步长,指定增量!
# decrby: 设置步长,指定减量!

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> 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> decr views
(integer) 0
127.0.0.1:6379> incrby views 10 # 可以设置步长,指定增量!
(integer) 10
127.0.0.1:6379> incrby views 10
(integer) 20
127.0.0.1:6379> decrby views 10 # 可以设置步长,指定减量!
(integer) 10
127.0.0.1:6379> decrby views 10
(integer) 0
===============================================================================

================================ 字符串范围 ====================================
# range: 范围
# getrange: 截取字符串
# setrange: 替换指定位置开始的字符串!

127.0.0.1:6379> set key1 "hello,redis" # 设置 key1 的值
OK
127.0.0.1:6379> get key1
"hello,redis"
127.0.0.1:6379> getrange key1 0 3 # 截取字符串 [0,3]
"hell"
127.0.0.1:6379> getrange key1 0 -1 # 获取全部的字符串 和 get key是一样的
"hello,redis"

# 替换
127.0.0.1:6379> set key2 chengguangxiang
OK
127.0.0.1:6379> get key2
"chengguangxiang"
127.0.0.1:6379> setrange key2 1 xx # 替换指定位置开始的字符串!
(integer) 15
127.0.0.1:6379> get key2
"cxxngguangxiang" 
===============================================================================

===============================================================================
# setex (set with expire) : 设置过期时间 
# setnx (set if not exist) : 不存在在设置 (在分布式锁中会常常使用!)
127.0.0.1:6379> setex key3 30 "hell" # 设置key3 的值为 hello,30秒后过期
OK
127.0.0.1:6379> ttl key3 
(integer) 26
127.0.0.1:6379> get key3
"hell"
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> setnx mykey "redis" # 如果mykey 不存在,创建mykey 成功显示: 1 ,失败显示:0
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "mysql" # 如果mykey存在,创建失败!成功显示: 1 ,失败显示:0
(integer) 0
127.0.0.1:6379> get mykey
"redis"
===============================================================================

============================== 批量设值 ========================================
# mset: 
# mget: 

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
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 k4
(nil)
===============================================================================

============================== 对象[重点] ======================================
# set user:1 {name:zhangsan,age:5}: 这只一个user:1对象,值为json字符来保存一个对象

# 这里的key是一个巧妙的设计: user:{id}:{filed} , 如此设计在Redis中是完全OK了!
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

# 场景: 可以用于文章浏览量
=============================== getset ========================================
# 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 mysql # 如果存在值,获取原来的值,并设置新的值
"redis"
127.0.0.1:6379> get db
"mysql"
===============================================================================

数据结构是相同的!

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

  • 计数器

  • 统计多单位的数量

  • 粉丝数

  • 对象缓存存储!

List(列表)open in new window

基本数据类型 列表

在redis里面,我们可以把list玩成 ,栈、队列、阻塞队列!

所有的list命令都是用 l开头的Redis命令不区分大小

================================= 左边/右边插入 ================================
# lpush: 将一个值或者多个值,插入到列表头部 (左)
# rpush: 将一个值或者多个值,插入到列表位部 (右)
# lrange: 获取list中值!

127.0.0.1:6379> keys *
(empty list or set)
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 # 获取list中值!
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 # 通过区间获取具体的值!
1) "three"
2) "two"
127.0.0.1:6379> rpush list chggx # 将一个值或者多个值,插入到列表位部 (右)
(integer) 4
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"
4) "chggx"
===============================================================================

================================= 移除 ========================================
# lpop: 移除list的第一个元素 (左边)
# rpop: 移除list的最后一个元素 (右边)

127.0.0.1:6379> keys *
1) "list"
127.0.0.1:6379> lrange list 0 -1 
1) "three"
2) "two"
3) "one"
4) "chggx"
127.0.0.1:6379> lpop list # 移除list的第一个元素 (左边)
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "chggx"
127.0.0.1:6379> rpop list  # 移除list的最后一个元素 (右边)
"chggx"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
===============================================================================

================================== 下标 =======================================
# lindex: 通过下标获得 list 中的某一个值!

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: 获取list列表长度

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
===============================================================================

================================ 移除指定的值 ==================================
# lrem : 移除指定的值! 取关 uid

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

=============================== 修剪(截取)trim =================================
# trim 修剪(截取指定值): list 截断 !

127.0.0.1:6379> keys *
(empty list or set)
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> lrange mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello3"
127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定的长度,这个list已经被改变了,截断了 只剩下截取的元素
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
===============================================================================

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

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hell01"
(integer) 2
127.0.0.1:6379> rpush mylist "hell02"
(integer) 3
127.0.0.1:6379> rpush mylist "hell03"
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hell01"
3) "hell02"
4) "hell03"
127.0.0.1:6379> rpoplpush mylist myotherlist # 移除列表的最后一个元素,将他移动到新的 列表中!
"hell03"
127.0.0.1:6379> lrange mylist 0 -1 # 查看原来的列表
1) "hello"
2) "hell01"
3) "hell02"
127.0.0.1:6379> lrange myotherlist 0 -1 # 查看目标列表中,确实存在改值!
1) "hell03"
===============================================================================

============================= exists/lset =====================================
# exists: 判断list列表是否存在
# lset: 将列表中指定下标的值替换为另外一个值,"更新操作"(key不存在时( ERR no such key),不能直接使用lset创建可以,需使用lpush/rpush. index下标不存在时(ERR index out of range),不能直接使用)

127.0.0.1:6379> keys * 
(empty list or set)
127.0.0.1:6379> exists list # 判断这个列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item # 如果不存在列表,我们使用lset去更新就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1 # 设置值 (左)
(integer) 1
127.0.0.1:6379> lrange list 0 0 # 获取下标"0"值
1) "value1"
127.0.0.1:6379> lset list 0 item # 下标"0", 如果存在,更新当前下标的值
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 (插入) ================================
# linsert: 将某个具体的value插入到列表中某个元素的前面或者后面!

127.0.0.1:6379> keys *
(empty list or set)
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> lrange mylist 0 -1 # 获取所有mylist值
1) "hello"
2) "world"
127.0.0.1:6379> linsert mylist before "world" "other" # 将某个具体的value插入到列表中某个元素的前面!
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1 # 获取所有mylist值
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert mylist after world after # 将某个具体的value插入到列表中某个元素的后面!
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1 # 获取所有mylist值
1) "hello"
2) "other"
3) "world"
4) "after"
===============================================================================

小结:

他实际上是一个链表,before Node after , left,right 都可以插入值

如果key 不存在,创建新的链表

如果key存在,新增内容

如果移除了所有值,空链表,也代表不存在!

在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点~

list列表应用场景: 消息排队消息队列 (Lpush Rpop) 栈( Lpush Lpop)!

Set(集合)open in new window

set中的值是不能重读的! set是不重复的.

============================= 基础 =======================================
# sadd: set集合中添加元素
# smembers: 查看指定set的所有值
# sismember: 判断某一个值是不是在set集合中

127.0.0.1:6379> sadd myset "hello" # set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd myset "world" 
(integer) 1
127.0.0.1:6379> sadd myset "chggx"
(integer) 1
127.0.0.1:6379> smembers myset # 查看指定set的所有值
1) "chggx"
2) "hello"
3) "world"
127.0.0.1:6379> sismember myset hello # 判断某一个值是不是在set集合中!
(integer) 1
127.0.0.1:6379> sismember myset redis
(integer) 0
===============================================================================

============================= scard (元素个数) =================================
# scard: 获取set集合中的内容元素个数!

127.0.0.1:6379> scard myset # 获取set集合中的内容元素个数!
(integer) 3
127.0.0.1:6379> sadd myset "hello" # set集合中添加元素
(integer) 0
127.0.0.1:6379> sadd myset "redis" # 说明 set 集合 的元素是不重复的
(integer) 1
127.0.0.1:6379> scard myset # 获取set集合中的内容元素个数!
(integer) 4
============================= srem (移除元素) ================================
# srem: 移除set集合中的指定元素

127.0.0.1:6379> smembers myset
1) "chggx"
2) "hello"
3) "redis"
4) "world"
127.0.0.1:6379> scard myset
(integer) 4
127.0.0.1:6379> srem myset chggx # 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> scard myset // 获取set集合中内容的元素个数
(integer) 3
127.0.0.1:6379> smembers myset // 查看set集合的值
1) "hello"
2) "redis"
3) "world"
===============================================================================

============================== srandmember ====================================
# set 无序不重复集合,抽随机
# srandmember: 随机抽取出指定个数元素

127.0.0.1:6379> smembers myset
1) "hello"
2) "redis"
3) "world"
127.0.0.1:6379> srandmember myset # 随机抽取出一个元素
"hello"
127.0.0.1:6379> srandmember myset 
"redis"
127.0.0.1:6379> srandmember myset 
"world"
127.0.0.1:6379> srandmember myset 2 # 随机抽取出指定个数元素
1) "redis"
2) "world"
127.0.0.1:6379> srandmember myset 2
1) "redis"
2) "world"
===============================================================================

============================== spop (随机删key) ================================
删除定的key,随机删除key!

127.0.0.1:6379> smembers myset
1) "hello"
2) "redis"
3) "world"
127.0.0.1:6379> spop myset # 随机删除一些set集合中的元素(弹出set集合中的元素)
"world"
127.0.0.1:6379> spop myset
"hello"
127.0.0.1:6379> smembers myset
1) "redis"
================================ smove =======================================
# smove: 将一个指定的值,移动到另外一个set集合!

127.0.0.1:6379> sadd myset "hell0"
(integer) 1
127.0.0.1:6379> sadd myset "world"
(integer) 1
127.0.0.1:6379> sadd myset "chggx"
(integer) 1
127.0.0.1:6379> smembers myset
1) "chggx"
2) "hell0"
3) "world"
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> smembers myset2
1) "set2"
127.0.0.1:6379> smove myset myset2 "chggx" #  将一个指定的值,移动到另外一个set集合!
(integer) 1
127.0.0.1:6379> smembers myset
1) "hell0"
2) "world"
127.0.0.1:6379> smembers myset2
1) "chggx"
2) "set2"
===============================================================================

================================ 并集 =========================================
 # 数字集合类: 
# 	- 差集 sdiff 
# 	- 交集 sinter
# 	- 并集 sunion

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> smembers key1
1) "b"
2) "c"
3) "a"
127.0.0.1:6379> smembers key2
1) "d"
2) "c"
3) "e"
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) "c"
2) "a"
3) "d"
4) "b"
5) "e"

# 场景:
# 微博,B站,共同关注!(并集)
# 微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
# 共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)
===============================================================================

Hashopen in new window

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

============================== 基础 ========================================
# hset: set一个具体 key-vlaue
# hget: 获取一个字段值
# hmset: set多个 key-vlaue
# hmget: 获取多个字段值
# hgetall: 获取全部的数据(以ley-value形式展示)
# hdel: 删除hash中指定key字段!对应的value值也就消失了!

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

=============================== 长度(hlen) ====================================
# hlen: 获取hash表的字段数量!

127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hlen myhash # 获取hash表的字段数量!
(integer) 2
===============================================================================

=============================== 指定字段是否存在 ================================
# hexists: 

127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hexists myhash field1 # 判断hash中指定字段是否存在!
(integer) 1
127.0.0.1:6379> hexists myhash field3
(integer) 0
===============================================================================

============================= 单独获取field/value ==============================
# hkeys: 只获得所有field 
# hvals: 只获得所有value

127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hkeys myhash # 只获得所有field
1) "field2"
2) "field1"
127.0.0.1:6379> hvals myhash # 只获得所有value
1) "world"
2) "hello"
===============================================================================

================================ 自增/自减======================================
incr/decr

127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> hincrby myhash field3 1 # 指定增量
(integer) 6
127.0.0.1:6379> hincrby myhash field3 1
(integer) 7
127.0.0.1:6379> hincrby myhash field3 -1
(integer) 6
127.0.0.1:6379> hsetnx myhash field4 hello # 如果不存在则可以设置
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 hello # 如果存在则不可以设置
(integer) 0
===============================================================================

hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息!

hash 更适合于对象的存储,String更加适合字符串存储!

Zset(有序集合)open in new window

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

================================ 基础 =========================================
# zadd: 添加一个/多个值
# zrange: 获取所有值

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"
===============================================================================

=============================== 排序如何实现 ===================================
# zrangebyscore: 由低到高排序
# zrevrange: [反转] 倒序排列

127.0.0.1:6379> zadd salary 2500 zhangsan # 添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 5000 lisi
(integer) 1
127.0.0.1:6379> zadd salary 500 wangwu
(integer) 1
# 语法: ZRANGEBYSCORE key min max
127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示全部的用户 从小到大!(-∞,+∞) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrevrange salary 0 -1  # 从大到进行排序!
1) "lisi"
2) "zhangsan"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 显示全部的用户并且附带成绩
1) "wangwu"
2) "500"
3) "zhangsan"
4) "2500"
5) "lisi"
6) "5000"
127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores # 显示工资小于2500员工的升序排序!
1) "wangwu"
2) "500"
3) "zhangsan"
4) "2500"
===============================================================================

================================ 移除(zrem) ===================================
# zrem: 移除有序集合中的指定元素
# zcard: 获取有序集合中的个数

127.0.0.1:6379> zrange salary 0 -1
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrem salary wangwu # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhangsan"
2) "lisi"
127.0.0.1:6379> zcard salary # 获取有序集合中的个数
(integer) 2
===============================================================================

=============================== zcount(统计) ==================================
# zcount: 获取指定区间的成员数量!

127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 2 world 3 chggx
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "hello"
2) "world"
3) "chggx"
127.0.0.1:6379> zcount myset 1 3 # 获取指定区间的成员数量!
(integer) 3
127.0.0.1:6379> zcount myset 1 2
(integer) 2
127.0.0.1:6379> zcount myset 1 1
(integer) 1
===============================================================================

案例思路:set 排序 存储班级成绩表,工资表排序!

普通消息,1, 重要消息 2,带权重进行判断!

排行榜应用实现,取Top N 测试!

2. 特殊数据类型

2.1 Geospatialopen in new window 地理位置

2.1.1 介绍

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

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

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

2.2.2 命令open in new window

redis Geospatial 6个命令

官方文档:https://www.redis.net.cn/order/3685.htmlopen in new window

  1. geoaddopen in new window
  • geoadd 添加地理位置
# 参数 key 值(经度、纬度、名称)
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai 
(integer) 1
127.0.0.1:6379> geoadd china:city 120.15 30.28 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.08 22.54 shenzhen
(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 118.76 32.04 nanjing 118.11 24.49 xiamen
(integer) 2

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

# 有效的经度从-180度到180度。

# 有效的纬度从-85.05112878度到85.05112878度。

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

  1. geoposopen in new window

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

127.0.0.1:6379> geopos china:city beijing # 获取指定的城市的经度和纬度!
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city hangzhou
1) 1) "120.15000075101852417"
   2) "30.2800007575645509"
127.0.0.1:6379> geopos china:city nanjing shenzhen
1) 1) "118.75999957323074341"
   2) "32.03999960287850968"
2) 1) "114.08000081777572632"
   2) "22.53999903789756587"
  1. geodistopen in new window
  • 返回两个给定位置之间的距离。

  • 单位:

    m 表示单位为米。

    km 表示单位为千米。

    mi 表示单位为英里。

    ft 表示单位为英尺。

127.0.0.1:6379> geodist china:city beijing shanghai km # 查看北京到上海的直线距离
"1067.3788"
127.0.0.1:6379> geodist china:city beijing hangzhou km # 查看北京到杭州的直线距离
"1122.7998"
127.0.0.1:6379> geodist china:city beijing chongqing km # 查看北京到重庆的直线距离
"1464.0708"
127.0.0.1:6379> geodist china:city beijing shenzhen km # 查看北京到深圳的直线距离
"1943.2550"
  1. georadiusopen in new window
  • 以给定的经纬度为中心, 找出某一半径内的元素

  • 应用:

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

127.0.0.1:6379> georadius china:city 110 30 500 km # 以110,30 这个经纬度为中心,寻 找方圆500km内的城市
1) "chongqing"
127.0.0.1:6379> georadius china:city 110 30 1000 km # 以110,30 这个经纬度为中心,寻 找方圆1000km内的城市
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "zhengzhou"
5) "nanjing"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist # 显示到中间距离的位置
1) 1) "chongqing"
   2) "341.9374"
2) 1) "shenzhen"
   2) "923.9364"
3) 1) "hangzhou"
   2) "976.4868"
4) 1) "zhengzhou"
   2) "630.2160"
5) 1) "nanjing"
   2) "864.9816"
127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord # 显示他人的定位信息
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "shenzhen"
   2) 1) "114.08000081777572632"
      2) "22.53999903789756587"
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"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 1
# 筛选出指定的结果!
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 2
# 筛选出指定的结果!
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "zhengzhou"
   2) "630.2160"
   3) 1) "113.65999907255172729"
      2) "34.74999926510690784"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 3
# 筛选出指定的结果!
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "zhengzhou"
   2) "630.2160"
   3) 1) "113.65999907255172729"
      2) "34.74999926510690784"
3) 1) "nanjing"
   2) "864.9816"
   3) 1) "118.75999957323074341"
      2) "32.03999960287850968"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist withcoord count 4
# 筛选出指定的结果!
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "zhengzhou"
   2) "630.2160"
   3) 1) "113.65999907255172729"
      2) "34.74999926510690784"
3) 1) "nanjing"
   2) "864.9816"
   3) 1) "118.75999957323074341"
      2) "32.03999960287850968"
4) 1) "shenzhen"
   2) "923.9364"
   3) 1) "114.08000081777572632"
      2) "22.53999903789756587"
  1. georadiusbymember open in new window [定位]
  • 找出位于指定元素周围的其他元素!
127.0.0.1:6379> georadiusbymember china:city beijjing 1000 km
1) "zhengzhou"
2) "nanjing"
3) "beijjing"
127.0.0.1:6379> georadiusbymember china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
3) "nanjing"
  1. geohashopen in new window
  • 命令 - 返回一个或多个位置元素的 Geohash 表示
  • 该命令将返回11个字符的Geohash字符串!
# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近!
127.0.0.1:6379> geohash china:city beijjing zhengzhou
1) "wx4fbxxfke0"
2) "ww0vdqh9mv0"

2.1.3 GEO 底层的实现原理

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

127.0.0.1:6379> zrange china:city 0 -1 # 查看地图中全部的元素
1) "chongqing"
2) "shenzhen"
3) "xiamen"
4) "hangzhou"
5) "shanghai"
6) "zhengzhou"
7) "nanjing"
8) "beijjing"
127.0.0.1:6379> zrem china:city xiamen # 移除指定元素!
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "zhengzhou"
6) "nanjing"
7) "beijjing"

2.2 Hyperloglogopen in new window

2.2.1 什么是基数?

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

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

2.2.2 简介

Redis 2.8.9 版本就更新了 Hyperloglog 数据结构!

Redis Hyperloglog 基数统计的算法!

2.2.3 优点

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

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

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

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

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

2.2.4 命令测试open in new window

# pfadd: 创建
# pfcount: 统计
# pfmerge: 合并(获取一个并集)

127.0.0.1:6379> pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey  # 统计 mykey 元素的基数数量
(integer) 10
127.0.0.1:6379> pfadd mykey2 i j z x c v b n m # 创建第二组元素 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 或者自己的数据类型即可!

2.3 Bitmapopen in new window 位图

2.3.1 位存储

场景: 统计用户信息,活跃,不活跃! 登录 、 未登录! 打卡,365打卡! 两个状态的,都可以使用Bitmaps!

Bitmap 位图,数据结构! 都是操作二进制位来进行记录,就只有0 和 1 两个状态!

365 天 = 365 bit 1字节 = 8bit 46 个字节左右!

2.3.2 测试

  1. 使用bitmap 来记录 周一到周日的打卡!
  • 周一:1 周二:0 周三:0 周四:1 ......
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(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
  1. 查看某一天是否有打卡!
127.0.0.1:6379> getbit sign 3 # 查看周四是否打卡
(integer) 1
127.0.0.1:6379> getbit sign 6 # 查看周日是否打卡
(integer) 0
127.0.0.1:6379> getbit sign 0 # 查看周一是否打卡
(integer) 1
  1. 统计操作,统计 打卡的天数!
127.0.0.1:6379> bitcount sign # 统计这周的打卡记录,就可以查看是否全勤
(integer) 3
127.0.0.1:6379> bitcount sign 0 5 # 统计周一到周六打卡记录
(integer) 3