Redis-06-五大基本(三大特殊)数据类型详解
Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
它支持多种类型的数据结构,如字符串(String),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)与范围查询,Bitmaps,Hyperloglogs 和地理空间(Geospatial)索引半径查询。
其中常见的数据结构类型有:String、List、Set、Hash、ZSet这5种。
Redis 内置了复制(Replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(Transactions) 和不同级别的磁盘持久化(Persistence),并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(High Availability)。
1.五大数据类型
String(字符串)
汇总:
set name xkx # 设置值
get name # 获取值
EXISTS name # 判断指定key是否存在
APPEND name hello # 往指定key中追加字符,如果key不存在则自动创建
STRLEN name # 查看指定key长度
INCR views # 自增1,也就是浏览量+1
DECR views # 自减1,也就是浏览量-1
INCRBY views 10 # 步长,指定增量为10,相当于浏览量+10
DECRBY views 5 # 步长,指定减量为5,相当于浏览量-5
GETRANGE name 0 3 # 截取字符串 [0,3]
GETRANGE name 0 -1 # 获取字符串,相当于get name
SETRANGE name 1 xx # 替换指定位置开始的字符串
setex name 30 hello # 设置name的值为hello,30秒后过期
setnx mykey redis # 如果mykey不存在,创建成功,存在则失败
mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
mget k1 k2 k3 # 同时获取多个值
# msetnx 如果key不存在才创建
msetnx k1 v1 k4 v4 # msetnx是一个原子性操作,要么都成功,要么都失败
set user:1 {name:zhangsan,age:3} # 设置一个user:1对象 ,值为json字符来保存一个对象
# 这里的key是一个巧妙地设计 user:{id}:{diled},如此设计在Redis中是完全OK的
mset user:2:name zhangsan user:2:age 2
mget user:2:name user:2:age
# 先获取db的值,在设置db=redis
getset db redis # 如果不存在,返回nil,并创建新的key
实例:
########################################################################
127.0.0.1:6379> set name xkx # 设置值
OK
127.0.0.1:6379> get name # 获取值
"xkx"
127.0.0.1:6379> EXISTS name # 判断指定key是否存在
(integer) 1
127.0.0.1:6379> APPEND name hello # 往指定key中追加字符,如果key不存在则自动创建
(integer) 8
127.0.0.1:6379> get name
"xkxhello"
127.0.0.1:6379> STRLEN name # 查看指定key长度
(integer) 8
########################################################################
# 浏览量应用
127.0.0.1:6379> set views 0 # views为浏览量,初始为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> DECR views # 自减1,也就是浏览量-1
(integer) 1
127.0.0.1:6379> INCR views
(integer) 2
127.0.0.1:6379> INCR views
(integer) 3
127.0.0.1:6379> INCR views
(integer) 4
127.0.0.1:6379> DECR views
(integer) 3
127.0.0.1:6379> DECR views
(integer) 2
127.0.0.1:6379> DECR views
(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> get views
"-1"
127.0.0.1:6379> INCRBY views 10 # 步长,指定增量为10,相当于浏览量+10
(integer) 9
127.0.0.1:6379> INCRBY views 10
(integer) 19
127.0.0.1:6379> DECRBY views 5 # 步长,指定减量为5,相当于浏览量-5
(integer) 14
########################################################################
# 截取字符串 range
127.0.0.1:6379> set name xkxfyy123
OK
127.0.0.1:6379> get name
"xkxfyy123"
127.0.0.1:6379> GETRANGE name 0 3 # 截取字符串 [0,3]
"xkxf"
127.0.0.1:6379> GETRANGE name 0 -1 # 获取字符串,相当于get name
"xkxfyy123"
# 替换字符串
127.0.0.1:6379> set name abcdefghijklmn
OK
127.0.0.1:6379> get name
"abcdefghijklmn"
127.0.0.1:6379> SETRANGE name 1 xx # 替换指定位置开始的字符串
(integer) 14
127.0.0.1:6379> get name
"axxdefghijklmn"
########################################################################
# setex(set with expire) # 设置过期时间
# setnx (set if not exist) # 如果不存在则设置
127.0.0.1:6379> setex name 30 hello # 设置name的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl name
(integer) 27
127.0.0.1:6379> get name
"hello"
127.0.0.1:6379> setnx mykey redis # 如果mykey不存在,创建成功
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> setnx mykey mongoDB # 如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> keys *
1) "mykey"
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) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3" # msetnx 如果key不存在才创建
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:3} # 设置一个user:1对象 ,值为json字符来保存一个对象
# 这里的key是一个巧妙地设计 user:{id}:{diled},如此设计在Redis中是完全OK的
127.0.0.1:6379> mset user:2:name zhangsan user:2:age 2
OK
127.0.0.1:6379> mget user:2:name user:2:age
1) "zhangsan"
2) "2"
########################################################################
getset # 先get再set
# 先获取db的值,在设置db=redis
127.0.0.1:6379> getset db redis # 如果不存在,返回nil,并创建新的key
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongoDB # 如果存在值,先获取旧值,再设置新值
"redis"
案例思路
String类似的使用场景:value可以是字符串或数字!!!
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储!
List(列表)
是列表,但是在Redis中,我们可以把list弄成栈,队列,阻塞队列!
所有的LIst命令都是L开头的(不区分大小写)
汇总
LPUSH list one # 将一个值或者多个值,插入到列表头部(左)
LRANGE list 0 -1 # 获取list中的所有值
LRANGE list 0 1 # 通过区间获取具体值
RPUSH list right # 将一个值或者多个值,插入到列表尾部(右)
LPOP list # 移除list的第一个元素
RPOP list # 移除list的最后一个元素
LINDEX list 1 #通过下标获取具体值(起始为0)
LLEN list # 返回列表长度
LREM list 2 three # 移除2个three,从头开始,因为里面只有1个了,所以返回1
LTRIM myList 1 2 # 通过下标截取指定的长度,保留[1,2]内容
RPOPLPUSH mylist myotherlist # 移除mylist列表最后一个元素,并且移动到另外一个myotherlist中
lset list 0 item # 修改指定下标处的值,如果列表或下标处不存在就会报错
LINSERT list before hello other # 将other插入到hello前面
LINSERT list after hello2 after # 将after插入到hello2后面
实例
########################################################################
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 right # 将一个值或者多个值,插入到列表尾部(右)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
########################################################################
LPOP
RPOP
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> LINDEX list 1 #通过下标获取具体值(起始为0)
"one"
127.0.0.1:6379> LINDEX list 0
"two"
########################################################################
Llen
127.0.0.1:6379> LLEN list # 返回列表长度
(integer) 2
########################################################################
移除指定的值!!!!!
取关 uuid
Lrem
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> LREM list 1 three # 移除1个three,从头开始
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> LREM list 2 three # 移除2个three,从头开始,因为里面只有1个了,所以返回1
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
########################################################################
trim 修剪
127.0.0.1:6379> RPUSH myList hello
(integer) 1
127.0.0.1:6379> RPUSH myList hello2
(integer) 2
127.0.0.1:6379> RPUSH myList hello3
(integer) 3 # 0 1 2 3
127.0.0.1:6379> RPUSH myList hello4 # hello hello2 hello3 hello4
(integer) 4
127.0.0.1:6379> LTRIM myList 1 2 # 通过下标截取指定的长度,保留[1,2]内容
OK
127.0.0.1:6379> LRANGE myList 0 -1
1) "hello2"
2) "hello3"
##########################################################################
rpoplpush # 移除列表最后一个元素,并且移动到另外一个list中
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> RPOPLPUSH mylist myotherlist # 移除列表最后一个元素,并且移动到另外一个list中
"hello2"
127.0.0.1:6379> LRANGE mylist 0 -1 # 查看原来的列表
1) "hello"
2) "hello1"
127.0.0.1:6379> LRANGE myotherlist 0 -1 # 查看目标列表
1) "hello2"
##########################################################################
# lset 将list中指定下标的值替换为另外一个值,更新操作!
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 value1
(integer) 1
127.0.0.1:6379> LRANGE list 0 0
1) "value1"
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 # 将具体的值插入到指定值的前面或后面
127.0.0.1:6379> LPUSH list hello
(integer) 1
127.0.0.1:6379> LPUSH list hello2
(integer) 2
127.0.0.1:6379> LINSERT list before hello other
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello2"
2) "other"
3) "hello"
127.0.0.1:6379> LINSERT list after hello2 after
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "hello2"
2) "after"
3) "other"
4) "hello"
小结
- 他实际上是一个链表,before Node after , left , right都可以插入值
- 如果key不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在!
- 在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点~
可以当作 消息排队!消息队列( Lpush Rpop ) ,栈( Lpush Lpop )
Set(集合)
其中的值不会重复
汇总
SADD myset hello # 如果没有,则先创建集合再添加元素,如果有直接添加元素
SMEMBERS myset # 查看集合中全部元素
SISMEMBER myset hello # 检查集合中存不存再某个元素
SCARD myset #获取set集合中元素个数
SREM myset hello # 移除set集合中的指定元素
SRANDMEMBER myset # 随机抽选出一个元素 无序不重复集合!抽随机!
SRANDMEMBER myset 2 # 随机抽选出指定个数的元素
SPOP myset # 随机删除一个元素
SPOP myset 3 # 随机删除指定个数元素
SMOVE myset myset2 hello1 #将myset集合中hello1的移动到myset2集合中
SDIFF key1 key2 # 两个的差集(以key1为基准)
SINTER key1 key2 # 交集:共同好友就可以这样实现
SUNION key1 key2 # 并集
实例
#########################################################################
SADD
SMEMBERS
SISMEMBER
127.0.0.1:6379> SADD myset hello # 如果没有,则先创建集合再添加元素,如果有直接添加元素
(integer) 1
127.0.0.1:6379> SADD myset xkx
(integer) 1
127.0.0.1:6379> SADD myset fyy
(integer) 1
127.0.0.1:6379> SMEMBERS myset # 查看集合中全部元素
1) "hello"
2) "fyy"
3) "xkx"
127.0.0.1:6379> SISMEMBER myset hello # 检查集合中存不存再某个元素
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0
#########################################################################
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 #获取set集合中元素个数
(integer) 2
127.0.0.1:6379> SMEMBERS myset # 查看集合中全部元素
1) "fyy"
2) "xkx"
########################################################################
set 无序不重复集合!抽随机!
127.0.0.1:6379> SRANDMEMBER myset # 随机抽选出一个元素
"xkx"
127.0.0.1:6379> SRANDMEMBER myset
"xkx"
127.0.0.1:6379> SRANDMEMBER myset
"fyy"
127.0.0.1:6379> SRANDMEMBER myset 2 # 随机抽选出指定个数的元素
1) "fyy"
2) "xkx"
########################################################################
删除指定的key,删除随机key!
127.0.0.1:6379> SMEMBERS myset
1) "xkx"
2) "hello5"
3) "hello"
4) "hello2"
5) "hello3"
6) "hello4"
127.0.0.1:6379> SPOP myset # 随机删除一个元素
"xkx"
127.0.0.1:6379> SPOP myset
"hello2"
127.0.0.1:6379> SPOP myset 3 # 随机删除指定个数元素
"hello"
"hello4"
"hello5"
########################################################################
将一个指定的值移动到另一个set集合中
127.0.0.1:6379> SMEMBERS myset
1) "hello1"
2) "hello4"
127.0.0.1:6379> SADD myset2 set2
(integer) 1
127.0.0.1:6379> SMOVE myset myset2 hello1 #将myset集合中hello1的移动到myset2集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "hello1"
2) "set2"
########################################################################
微博,B站,共同关注!(并集)
数字集合类:
- 差集 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> SDIFF key1 key2 # 两个的差集(以key1为基准)
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) "e"
3) "c"
4) "b"
5) "d"
########################################################################
案例思路
微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)
Hash(哈希)
key—Map! 本质和string没有太大区别
汇总
HSET myhash field1 xkx # set一个具体的key-value,不可重复
hget myhash field1 # 获取一个字段值
HMSET myhash field1 hello field2 world #set多个key-value
HMGET myhash field1 field2 #获取多个字段值
HGETALL myhash # 显示全部数据
HDEL myhash field1 # 删除指定的字段,对应的value也没了
HLEN myhash # 获取内容长度
HEXISTS myhash field2 # 获取指定字段是否存在
HKEYS myhash # 获取所有的field
HVALS myhash # 获取所有的value
HINCRBY myhash field3 1 # 自增 +1
HINCRBY myhash field3 -1 # 自减 -1
HSETNX myhash field xkx # 如果不存在则可以设置,如果存在则不可以设置
实例
################################################################################
127.0.0.1:6379> HSET myhash field1 xkx # set一个具体的key-value,不可重复
(integer) 1
127.0.0.1:6379> hget myhash field1 # 获取一个字段值
"xkx"
127.0.0.1:6379> HMSET myhash field1 hello field2 world #set多个key-value
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 # 删除指定的字段,对应的value也没了
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
################################################################################
hlen
127.0.0.1:6379> HLEN myhash # 获取内容长度
(integer) 1
################################################################################
127.0.0.1:6379> HEXISTS myhash field2 # 获取指定字段是否存在
(integer) 1
################################################################################
127.0.0.1:6379> HKEYS myhash # 获取所有的field
1) "field2"
127.0.0.1:6379> HVALS myhash # 获取所有的value
1) "world"
################################################################################
incr
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1 # 自增 +1
(integer) 6
127.0.0.1:6379> HINCRBY myhash field3 -1 # 自减 -1
(integer) 5
127.0.0.1:6379> HSETNX myhash field xkx # 如果不存在则可以设置
(integer) 1
127.0.0.1:6379> HSETNX myhash field xkx # 如果存在则不可以设置
(integer) 0
################################################################################
案例思路
Hash变更的数据 user name age 尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,String更适合字符串的存储!
127.0.0.1:6379> hset user:1 name xkx
(integer) 1
127.0.0.1:6379> hget user:1 name
"xkx"
127.0.0.1:6379> HMSET user:1 name xkx age 20
OK
127.0.0.1:6379> HKEYS user:1
1) "name"
2) "age"
127.0.0.1:6379> HVALS user:1
1) "xkx"
2) "20"
127.0.0.1:6379> hget user:1 name
"xkx"
127.0.0.1:6379> hget user:1 age
"20"
Zset(有序集合)
在set的基础上,增加了一个值 set k1 v1 , zset k1 score1 v1
汇总:
ZADD myzset 1 one # 添加一个值
ZADD myzset 2 two 3 three # 添加多个个值
ZRANGE myzset 0 -1
ZRANGEBYSCORE salary -inf +inf # 查看负无穷到正无穷的所有值,按工资升序排列
ZREVRANGEBYSCORE salary +inf -inf # 查看正无穷到负无穷的所有值,按工资降序排列
ZRANGEBYSCORE salary -inf 2500 withscores #负无穷-2500的人排序,并显示信息
ZREM salary lisi # 移除有序集合中指定元素
ZCARD salary # 获取有序集合中的个数
ZCOUNT salary 500 1100 #获取指定区间的个数[500,1100],根据score
实例:
127.0.0.1:6379> ZADD myzset 1 one # 添加一个值
(integer) 1
127.0.0.1:6379> ZADD myzset 2 two 3 three # 添加多个个值
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
########################################################################
实例:按工资排序(score存储排序根据)
127.0.0.1:6379> ZADD salary 2500 zhangsan # zhangsan 工资2500
(integer) 1
127.0.0.1:6379> ZADD salary 5000 lisi #lisi 工资 5000
(integer) 1
127.0.0.1:6379> ZADD salary 1000 xkx # xkx工资1000
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 查看负无穷到正无穷的所有值,按工资升序排列
1) "xkx"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf# 查看正无穷到负无穷的所有值,按工资降序排列
1) "lisi"
2) "zhangsan"
3) "xkx"
127.0.0.1:6379> ZRANGEBYSCORE salary 500 2500 # 500-2500 的人排序
1) "xkx"
2) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores #负无穷-2500的人排序,并显示信息
1) "xkx"
2) "1000"
3) "zhangsan"
4) "2500"
#################################################################################
# 移除rem中的元素
127.0.0.1:6379> ZREM salary lisi # 移除有序集合中指定元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "xkx"
2) "zhangsan"
127.0.0.1:6379> ZCARD salary # 获取有序集合中的个数
(integer) 2
####################################################################################
127.0.0.1:6379> ZCOUNT salary 500 1100 #获取指定区间的个数[500,1100],根据score
(integer) 1
案例思路
set排序 存储班级成绩表,工资表排序!!!
普通消息 1,重要消息 2,带权重进行判断!!!
排行榜应用实现,取Top N测试!!!
2.三大特殊数据类型
geospatial地理位置
朋友的定位,附近的人,打车距离计算??
Redis的Geo在Redis3.2版本就推出了!这个功能可以推算地理位置信息,两地之间的距离,方圆几里的人!
查询经纬度:http://www.jsons.cn/lngcode/
- 有效的经度从-180度到180度。
- 有效的纬度从-85.05112878度到85.05112878度。
当坐标位置超出上述指定范围时,该命令将会返回一个错误。
geoadd
# geoadd 添加城市地理位置
# 规则:南北两极无法添加,我们一般会下载城市数据,使用java程序一次性导入!
# 参数 key 值(经度、纬度、名称)
127.0.0.1:6379> GEOADD Chine:city 116.75192 36.55352 jinan
(integer) 1
127.0.0.1:6379> GEOADD Chine:city 116.80542 35.7599 taian
(integer) 1
127.0.0.1:6379> GEOADD Chine:city 116.43432 37.16632 pingyuan
(integer) 1
127.0.0.1:6379> GEOADD Chine:city 113.280637 23.125178 guangzhou 121.472644 31.231706 shanghai
(integer) 2
geopos
获取当前定位,一定是一个坐标值
127.0.0.1:6379> GEOPOS Chine:city pingyuan # 获取指定城市的经纬度,可以获取多个
1) 1) "116.43432050943374634"
2) "37.16632106437197791"
geodist
两地之间的距离!
指定单位的参数 unit 必须是以下单位的其中一个:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
如果用户没有显式地指定单位参数, 那么 GEODIST
默认使用米作为单位。
127.0.0.1:6379> GEODIST Chine:city pingyuan taian km # 平原到泰安的直线距离,单位km
"159.9139"
georadius
我附近的人? (需要先获取附近的人的地址,定位!)通过半径来查询
127.0.0.1:6379> GEORADIUS Chine:city 110 30 1000 km # 获取距离100 30经纬度1000km内的城市
1) "guangzhou"
2) "taian"
3) "pingyuan"
4) "jinan"
127.0.0.1:6379> GEORADIUS Chine:city 110 30 900 km
1) "guangzhou" # 显示出距离km
127.0.0.1:6379> GEORADIUS Chine:city 110 30 900 km withdist
1) 1) "guangzhou"
2) "831.2636" #显示距离km #显示城市的坐标
127.0.0.1:6379> GEORADIUS Chine:city 110 30 900 km withdist withcoord
1) 1) "guangzhou"
2) "831.2636"
3) 1) "113.28063815832138062"
2) "23.12517743834835215" # 只显示前三个符合的
127.0.0.1:6379> GEORADIUS Chine:city 110 30 1000 km withdist withcoord count 3
1) 1) "guangzhou"
2) "831.2636"
3) 1) "113.28063815832138062"
2) "23.12517743834835215"
2) 1) "taian"
2) "902.0122"
3) 1) "116.80542021989822388"
2) "35.75990061245884277"
3) 1) "jinan"
2) "961.4590"
3) 1) "116.75192087888717651"
2) "36.5535192727267102"
GEORADIUSBYMEMBER
找出位于指定范围内的元素,中心点是由给定的位置元素决定
127.0.0.1:6379>GEORADIUSBYMEMBER Chine:city pingyuan 1000 km#找出位于指定元素1000km内的元素
1) "taian"
2) "pingyuan"
3) "jinan"
4) "shanghai"
GEOHASH
返回一个或多个位置元素的 Geohash 表示
该命令将返回11个字符的Geohash字符串
# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,则距离越近
127.0.0.1:6379> GEOHASH Chine:city taian pingyuan
1) "ww753vzhe80"
2) "wwdg3tbvs20"
ZEO底层实现原理(Zset)
其实就是Zset !我么可以使用Zset命令来操作GEO!
127.0.0.1:6379> ZRANGE Chine:city 0 -1 # 查看地图中全部元素
1) "guangzhou"
2) "shanghai"
3) "taian"
4) "pingyuan"
5) "jinan"
127.0.0.1:6379> ZREM Chine:city shanghai # 移除指定元素
(integer) 1
127.0.0.1:6379> ZRANGE Chine:city 0 -1
1) "guangzhou"
2) "taian"
3) "pingyuan"
4) "jinan"
Hyperloglog(基数统计)
什么是基数?
A{1,3,5,7,8,7} = 5
B{1,3,5,7,8} = 5
基数(不重复的元素) = 5,可以接受误差!
简介:
Redis2.8.9版本更新了Hyperloglog数据结构!
RedisHyperloglog是一个基数统计的算法!
优点:占用的内存是固定,2^64不同的元素的技术,只需要12KB内存,如果要从内存角度来比较的话Hyperloglog首选!
网页的UV(一个人访问一个网站多次,但还是算作一个人!)
传统的方式,set保存的用户的id,然后就可以统计set中的元素数量作为标准判断!
这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了基数,而不是保存用户id;
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 h g h a s d c 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) 12
如果允许容错,那就一定可以使用Hyperloglog !
如果不允许容错,那就使用set或者自己的数据类型即可!
Bitmaps
位存储
同级疫情感染人数:感染的用1,没感染的用0
统计用户信息,活跃的和不活跃的!登录的,未登录的!打卡,365打卡!
两个状态的都可以使用Bitmaps
Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有·0和1两个状态!
365天 = 365 bit 1字节 = 8bit 存储一个人365天的打卡数据,只需要46个字节左右!!!!!
测试实例(打卡)
使用Bitmaps来记录周一到周日的打卡情况
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 1
(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 6
(integer) 0
统计操作,统计打卡的天数!
127.0.0.1:6379> BITCOUNT sign # 统计这周的打卡记录,就可以看到是否全勤
(integer) 4