三、五大数据类型
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
1、常见命令
127.0.0.1:6379[3]> keys * # 查看所有的key
(empty array)
127.0.0.1:6379[3]> clear # 清屏
127.0.0.1:6379[3]> set name zyy # set key
OK
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> set age 1
OK
127.0.0.1:6379[3]> keys *
1) "age"
2) "name"
127.0.0.1:6379[3]> exists name # 判断key是否存在 1存在,0不存在
(integer) 1
127.0.0.1:6379[3]> exists name1
(integer) 0
127.0.0.1:6379[3]> move name 1 # 将key移动到1号数据库
(integer) 1
127.0.0.1:6379[3]> keys *
1) "age"
127.0.0.1:6379[3]> select 1 # 切换1号数据库
OK
127.0.0.1:6379[1]> keys *
1) "name"
127.0.0.1:6379[1]> get name # get value
"zyy"
127.0.0.1:6379[1]> select 3
OK
127.0.0.1:6379[3]> keys *
1) "age"
127.0.0.1:6379[3]> ttl name # 返回key的过期时间,-2 代表key不存在,-1代表存在可以,但是没有设置过期时间
(integer) -2
127.0.0.1:6379[3]> ttl age
(integer) -1
127.0.0.1:6379[3]> set name3 3
OK
127.0.0.1:6379[3]> keys *
1) "age"
2) "name3"
127.0.0.1:6379[3]> set name zyy
OK
127.0.0.1:6379[3]> keys *
1) "age"
2) "name"
3) "name3"
127.0.0.1:6379[3]> expire name 10 #设置key的过期时间,单位秒
(integer) 1
127.0.0.1:6379[3]> ttl name
(integer) 6
127.0.0.1:6379[3]> ttl name
(integer) 3
127.0.0.1:6379[3]> ttl name
(integer) 2
127.0.0.1:6379[3]> ttl name
(integer) 1
127.0.0.1:6379[3]> ttl name
(integer) 1
127.0.0.1:6379[3]> ttl name
(integer) -2
127.0.0.1:6379[3]> keys *
1) "age"
2) "name3"
127.0.0.1:6379[3]> type age # 查看key的数据类型
string
127.0.0.1:6379[3]> del k1 # 删除已存在的键。不存在的 key 会被忽略。
2、String(字符串)
#################################################
## 设置值 获取值 字符串长度 追加
127.0.0.1:6379> set key1 v1 # 设置值
OK
127.0.0.1:6379> get key1 # 获取值
"v1"
127.0.0.1:6379> keys * # 查看所有的key
1) "key1"
127.0.0.1:6379> exists key1 # 判断key是否存在,存在返回1 ,不存在返回0
(integer) 1
127.0.0.1:6379> exists key2
(integer) 0
127.0.0.1:6379> append key1 " hello" # 追加字符串,返回总长度 当key存在就追加,当key不存在就相当于set key
(integer) 8
127.0.0.1:6379> get key1
"v1 hello"
127.0.0.1:6379> strlen key1 # 获取字符串的长度
(integer) 8
127.0.0.1:6379> strlen key2
(integer) 0
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> append key1 ",zyy"
(integer) 12
127.0.0.1:6379> strlen key1
(integer) 12
127.0.0.1:6379> append key2 "zyy"
(integer) 3
127.0.0.1:6379> get key1
"v1 hello,zyy"
127.0.0.1:6379> get key2
"zyy"
#################################################
## 自增 自检 ###
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views # 自增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
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> decr views
(integer) -2
127.0.0.1:6379> get views
"-2"
127.0.0.1:6379> incrby views 10 # 可以设置步长,指定增量
(integer) 8
127.0.0.1:6379> decrby views 5
(integer) 3
#################################################
## 截取字符串 替换字符串
127.0.0.1:6379> set key1 "hello,zyy"
OK
127.0.0.1:6379> get key1
"hello,zyy"
127.0.0.1:6379> getrange key1 0 3 # 截取字符串[0,3]
"hell"
127.0.0.1:6379> getrange key1 0 -1 # 获取全部字符串 和 get key 一样
"hello,zyy"
127.0.0.1:6379> set key2 123456
OK
127.0.0.1:6379> get key2
"123456"
127.0.0.1:6379> setrange key2 1 bcd # 替换指定位置开始的字符串
(integer) 6
127.0.0.1:6379> get key2
"1bcd56"
127.0.0.1:6379>
#################################################
## 设置过期时间 setnx可用于分布式锁
127.0.0.1:6379> setex key1 30 "hello" # 设置key1的值为hello 并且30秒后过期
OK
127.0.0.1:6379> ttl key1 # 剩余时间
(integer) 24
127.0.0.1:6379> ttl key1
(integer) 22
127.0.0.1:6379> setnx key2 "123" # 如果key2不存在,就创建key2,创建成功,返回1
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
127.0.0.1:6379> setnx key2 "456" # 如果key2存在,就创建key2失败,返回0
(integer) 0
127.0.0.1:6379>
#################################################
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> mget k1 k2 k3 k4
1) "v1"
2) "v2"
3) "v3"
4) (nil)
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作,要么一起成功,要么一起失败!
(integer) 0
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379> set user:1 {name:zyy,age:18} # 设置一个user:1 对象,值为json字符来保存一个对象
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
4) "user:1"
127.0.0.1:6379> get user:1:name
(nil)
127.0.0.1:6379> get user:1
"{name:zyy,age:18}"
127.0.0.1:6379> set user:2 {name:zyy2,age:18}
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
4) "user:1"
5) "user:2"
127.0.0.1:6379> mset user:1:name zyy user:1:age 18 # 这里的key是一个巧妙的设计: user:{id}:{filed} , 如此设计在Redis中是完全OK了!
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
4) "user:1"
5) "user:1:age"
6) "user:1:name"
7) "user:2"
127.0.0.1:6379> mget user:1:name user:1:age
1) "zyy"
2) "18"
#################################################
## getset 先get再set
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> getset k1 v1 # 先get,再set 如果一开始key就不存在,就返回nil
(nil)
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> getset k1 1 # # 先get,再set 如果一开始值存在,就反正这个值(返回的旧值,设置的新值)
"v1"
127.0.0.1:6379> get k1
"1"
127.0.0.1:6379>
String类似的使用场景:value除了是我们的字符串还可以是我们的数字!
- 计数器
- 粉丝数
- 对象缓存存储
3、List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序。按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
在redis里面,我们可以把list玩成 栈、队列、阻塞队列!
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> lpush list a b c # 将一个或者多个值插入列表头部(左)
(integer) 3
127.0.0.1:6379> lrange list 0 1 # 获取指定范围的列表
1) "c"
2) "b"
127.0.0.1:6379> lrange list 0 -1 # 获取列表中的所有值
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> rpush list2 a b c # 将一个或者多个值插入列表尾部(右)
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> rpush list 1 2 3
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> rrange list 0 -1 # 没有rrange这个命令哦
(error) ERR unknown command 'rrange', with args beginning with: 'list' '0' '-1'
127.0.0.1:6379> lpop list # 移除list第一个元素
"1"
127.0.0.1:6379> lrange list 0 -1 #移除list最后一个元素
1) "2"
2) "3"
127.0.0.1:6379> rpop list
"3"
127.0.0.1:6379> lrange list 0 -1
1) "2"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange list
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lindex list 0 # 通过下标获得 list 中的某一个值!
"1"
127.0.0.1:6379> lindex list 5
(nil)
127.0.0.1:6379> lindex list 3
"4"
#################################################
127.0.0.1:6379> clear
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> llen list # 返回列表长度
(integer) 4
127.0.0.1:6379>
#################################################
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> llen list
(integer) 4
127.0.0.1:6379> lrem list 1 1
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> lrem list 2 1
(integer) 0
127.0.0.1:6379> lpush list 1 1
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "1"
3) "2"
4) "3"
5) "4"
127.0.0.1:6379> lrem list 1 2
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "1"
3) "3"
4) "4"
127.0.0.1:6379> lrem list 2 1 # 移除list集合中指定个数的value,精确匹配
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "4"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> ltrim list 1 2 # 通过下标截取指定的长度,这个list已经被改变了,截断了 只剩下截取的元素!
OK
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "3"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> rpoplpush list list2 # 移除列表的最后一个元素,将他移动到新的列表的头部!
"4"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> lrange list2 0 -1
1) "4"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> exists list # 判断列表是否存在,返回1就是存在, 返回0就是不存在
(integer) 1
127.0.0.1:6379> exists list2
(integer) 0
127.0.0.1:6379> lset list 0 a # 替换这个下面对应的值
OK
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lset list2 0 a # 替换时,列表不存在报这个错误
(error) ERR no such key
127.0.0.1:6379> lset list 4 a
(error) ERR index out of range # 替换时,下标越界报这个错误
127.0.0.1:6379>
#################################################
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 4
127.0.0.1:6379> linsert list before 1 0 # 将某个具体的value插入到列把你中某个元素的前面或者后面!
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
127.0.0.1:6379> linsert list after 4 5
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
127.0.0.1:6379>
小结
- 他实际上是一个链表,before Node after , left,right 都可以插入值
- 如果key 不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点~
消息队列(Lpush Rpop)
栈( Lpush Lpop)
4、Set集合
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> sadd setkey1 1 2 3 4 # set集合中添加元素
(integer) 4
127.0.0.1:6379> smembers setkey1 # 查看指定set的所有值
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> sismember setkey1 1 # 判断某一个值是不是在set集合中! 返回1代表存在,返回0代表不存在
(integer) 1
127.0.0.1:6379> sismember setkey1 5
(integer) 0
127.0.0.1:6379> sadd setkey1 5
(integer) 1
127.0.0.1:6379> smembers setkey1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> sadd setkey1 1 2 # set集合不可添加重复的值
(integer) 0
127.0.0.1:6379> smembers setkey1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> scard setkey1 # 获取set集合中的内容元素个数!
(integer) 5
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> srem set1 1 # 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> smembers set1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> scard set1
(integer) 3
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> srandmember set1 # 随机抽选出一个元素
"3"
127.0.0.1:6379> srandmember set1
"1"
127.0.0.1:6379> srandmember set1 2 # 随机抽选出指定个数的元素
1) "2"
2) "1"
127.0.0.1:6379> srandmember set1 2
1) "3"
2) "2"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> spop set1 # 随机删除一些set集合中的元素!
"1"
127.0.0.1:6379> spop set1
"3"
127.0.0.1:6379> spop set1 2 # 随机删除指定个数的元素
1) "2"
2) "4"
127.0.0.1:6379> spop set1
(nil)
127.0.0.1:6379> smembers set1
(empty array)
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
#################################################
127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> smove set1 set2 1 # 将集合中的一个指定的值,移动到另外一个set集合!
(integer) 1
127.0.0.1:6379> smembers set1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> smembers set2
1) "1"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd set2 3 4 5 6
(integer) 4
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> smembers set2
1) "3"
2) "4"
3) "5"
4) "6"
127.0.0.1:6379> sdiff set1 set2 # 差集
1) "1"
2) "2"
127.0.0.1:6379> sinter set1 set2 # 交集 通用好友就可以这样实现
1) "3"
2) "4"
127.0.0.1:6379> sunion set1 set2 #并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379>
5、Hash(哈希)
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
#################################################
127.0.0.1:6379> hset myhash1 f1 v1 # set一个具体 key-vlaue
(integer) 1
127.0.0.1:6379> hget myhash1 f1 # 获取一个字段值
"v1"
127.0.0.1:6379> hmset myhash2 f1 v1 f2 v2 # set多个 key-vlaue
OK
127.0.0.1:6379> keys *
1) "myhash2"
2) "myhash1"
127.0.0.1:6379> hmget myhash2 f1 f2 # 获取多个字段值
1) "v1"
2) "v2"
127.0.0.1:6379> hgetall myhash2 # 获取全部的数据
1) "f1"
2) "v1"
3) "f2"
4) "v2"
127.0.0.1:6379> hdel myhash2 f1 # 删除hash指定key字段!对应的value值也就消失了!
(integer) 1
127.0.0.1:6379> hgetall myhash2
1) "f2"
2) "v2"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> hmset myhash1 f1 v1 f2 v2
OK
127.0.0.1:6379> hgetall myhash1
1) "f1"
2) "v1"
3) "f2"
4) "v2"
127.0.0.1:6379> hlen myhash1 # 获取hash表的字段数量!
(integer) 2
127.0.0.1:6379>
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> hmset myhash1 f1 v2 f2 v2
OK
127.0.0.1:6379> hgetall myhash1
1) "f1"
2) "v2"
3) "f2"
4) "v2"
127.0.0.1:6379> hexists myhash1 f1 # 判断hash中指定字段是否存在 返回1说明存在,返回0说明不存在
(integer) 1
127.0.0.1:6379> hexists myhash1 f3
(integer) 0
127.0.0.1:6379>
#################################################
127.0.0.1:6379> hmset myhash1 f1 v1 f2 v2
OK
127.0.0.1:6379> hkeys myhash1 # 只获得所有field
1) "f1"
2) "f2"
127.0.0.1:6379> hvals myhash1 # 只获得所有value
1) "v1"
2) "v2"
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> hset myhash1 f1 1
(integer) 1
127.0.0.1:6379> hgetall myhash1
1) "f1"
2) "1"
127.0.0.1:6379> hincrby myhash1 f1 1 #指定增量 自增
(integer) 2
127.0.0.1:6379> hincrby myhash1 f1 1
(integer) 3
127.0.0.1:6379> hincrby myhash1 f1 3
(integer) 6
127.0.0.1:6379> hincrby myhash1 f1 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash2 f1 v1 # 如果field不存在,则设置成功,返回1
(integer) 1
127.0.0.1:6379> hgetall myhash2
1) "f1"
2) "v1"
127.0.0.1:6379> hsetnx myhash2 f1 v11 #如果field存在,则设置失败,返回1
(integer) 0
127.0.0.1:6379> hsetnx myhash2 f2 v2
(integer) 1
127.0.0.1:6379>
hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息!
hash 更适合于对象的存储,String更加适合字符串存储!
6、Zset(有序集合)
#################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> zadd myset 1 a # 添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 b
(integer) 1
127.0.0.1:6379> zadd myset 3 c 4 d # 添加多个值
(integer) 2
127.0.0.1:6379> zrange myset 0 -1 # 获取所有的值
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> zadd salary 60 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 80 lisi
(integer) 1
127.0.0.1:6379> zadd salary 50 wangwu
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示全部的用户 从小到大!(-inf 代表负无穷 +inf代表正无穷)
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrevrange salary 0 -1 # 从大大小排序
1) "lisi"
2) "zhangsan"
3) "wangwu"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #从小到大显示所有的用户并附带薪资
1) "wangwu"
2) "50"
3) "zhangsan"
4) "60"
5) "lisi"
6) "80"
127.0.0.1:6379> zrangebyscore salary -inf 60 withscores # 显示薪资小于等于60的用户并附带薪资
1) "wangwu"
2) "50"
3) "zhangsan"
4) "60"
127.0.0.1:6379>
#################################################
127.0.0.1:6379> zadd salary 5000 zhangsan 6000 lisi 10000 wangwu 3000 zhaoliu
(integer) 4
127.0.0.1:6379> zrange salary 0 -1
1) "zhaoliu"
2) "zhangsan"
3) "lisi"
4) "wangwu"
127.0.0.1:6379> zrem salary lisi # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhaoliu"
2) "zhangsan"
3) "wangwu"
127.0.0.1:6379> zcard salary # 获取有序集合中的个数
(integer) 3
127.0.0.1:6379>
#################################################
127.0.0.1:6379> zadd myset 1 a 2 b 3 c
(integer) 3
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 2 3
(integer) 2
127.0.0.1:6379>
#################################################
其余的一些api,可以去查询官方文档
案例思路:
-
set 排序、存储班级成绩,工资表排序
-
加权:1-重要消息 0-普通消息
-
排行榜应用实现,取top 10
四、三种特殊数据类型
Redis在3.2版本中加入了地理空间(geospatial)以及索引半径查询的功能
主要用在需要地理位置的应用上
朋友的定位,附近的人,打车距离计算
查询城市经纬度:www.jsons.cn/lngcode/
geodd 功能说明: 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
# getadd 添加地理位置
# 规则:两级无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
# 有效的经度从-180度到180度。 有效的纬度从-85.05112878度到85.05112878度。 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
127.0.0.1:6379> keys *
(empty array)
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 106.50 29.53 chongqin 125.14 42.92 xian
(integer) 3
geopos 功能说明: 从key里返回所有给定位置元素的位置(经度和纬度)
GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。
当给定的位置元素不存在时, 对应的数组项为空值
127.0.0.1:6379> geopos china:city xian
1) 1) "125.13999849557876587"
2) "42.92000122112879268"
geodist 两人之间的距离!
功能说明
- 返回两个给定位置之间的距离,如果两个位置之间的其中一个不存在, 那么命令返回空值
- 指定单位的参数 unit 必须是以下单位的其中一个
- m 表示单位为米(默认值)
- km 表示单位为千米
- mi 表示单位为英里
- ft 表示单位为英尺
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.3788"
georadius
我附近的人? (获得所有附近的人的地址,定位!)通过半径来查询!
以给定的经纬度为中心, 返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素
在给定以下可选项时, 命令会返回额外的信息:
-
withdist
在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
-
withcoord
将位置元素的经度和维度也一并返回。
-
withhash
以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。 命令默认返回未排序的位置元素。
127.0.0.1:6379> georadius china:city 110 30 1000 km # 以110,30 这个经纬度为中心,寻找方圆1000km内的城市
1) "chongqi"
2) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 400 km
1) "chongqi"
127.0.0.1:6379> georadius china:city 110 30 400 km withdist # 显示直线距离
1) 1) "chongqi"
2) "341.9374"
127.0.0.1:6379> georadius china:city 110 30 400 km withcoord # 显示经纬度
1) 1) "chongqi"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 30 400 km withhash
1) 1) "chongqi"
2) (integer) 4026042091628984
127.0.0.1:6379> georadius china:city 110 30 400 km withcoord count 1 # 筛选出指定数量的结果
1) 1) "chongqi"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord count 2
1) 1) "chongqi"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
2) 1) "hangzhou"
2) 1) "120.15000075101852417"
2) "30.2800007575645509"
georadiusbymember
功能说明: 这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点指定成员的位置被用作查询的中心
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km # 以北京为中心,附近1000米的城市
1) "beijing"
2) "xian"
geohash
该命令将返回11个字符的Geohash字符串!
# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近!
127.0.0.1:6379> GEOHASH china:city beijing
1) "wx4fbxxfke0"
geo底层的实现原理其实就是zset!我们可以使用zset命令来操作geo!
127.0.0.1:6379> zrange china:city 0 -1 # 查看全部的元素
1) "chongqi"
2) "hangzhou"
3) "shanghai"
4) "beijing"
5) "xian"
127.0.0.1:6379> zrem china:city xian # 移除指定的元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqi"
2) "hangzhou"
3) "shanghai"
4) "beijing"
127.0.0.1:6379>
2、hyperloglog
什么是基数
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8},
基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
简介
Redis 2.8.9 版本就更新了 Hyperloglog 数据结构!
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
网页的UV 一个人访问一个网站多次,但是还是算作一个人!)
传统的方式, set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断 !
这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;
测试使用
127.0.0.1:6379> pfadd mykey a b c d e # 创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey # 统计 mykey 元素的基数数量
(integer) 5
127.0.0.1:6379> pfadd mykey2 e d f g h k # 创建第二组元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 6
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 # 合并两组 mykey mykey2 ---> mykey3 并集
OK
127.0.0.1:6379> pfcount mykey3
(integer) 9
127.0.0.1:6379>
0.81% 错误率! 统计UV任务,可以忽略不计的!
如果允许容错,那么一定可以使用 Hyperloglog
如果不允许容错,就使用 set 或者自己的数据类型即可!
3、bitmap
BitMap 原本的含义是用一个比特位来映射某个元素的状态。由于一个比特位只能表示 0 和 1 两种状态,所以 BitMap 能映射的状态有限,但是使用比特位的优势是能大量的节省内存空间。
应用场景
- 用户签到
- 统计活跃用户(用户登陆情况)
- 统计用户是否在线
- 实现布隆过滤器
测试
使用bitmap 来记录 周一到周日的打卡!
7天打卡
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(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> setbit sign 7 1
(integer) 0
查看某一天的打开情况
127.0.0.1:6379> getbit sign 1
(integer) 1
127.0.0.1:6379> getbit sign 2
(integer) 1
127.0.0.1:6379> getbit sign 4
(integer) 0
统计操作,统计 打卡的天数!
127.0.0.1:6379> bitcount sign # 统计这周的打卡记录,就可以看到是否有全勤!
(integer) 3
127.0.0.1:6379>