• 5.Redis类型详解


    五大基本数据类型

    String


    1. 追加字符串,字符串长度
    127.0.0.1:6379> set k1 v1
    OK
    127.0.0.1:6379> get k1
    "v1"
    127.0.0.1:6379> keys *
    1) "k1"
    127.0.0.1:6379> exists k1
    (integer) 1
    127.0.0.1:6379> APPEND k1 "hello" # 追加字符串,如果当前字符串不存在则相当于set key
    (integer) 7
    127.0.0.1:6379> get k1
    "v1hello"
    127.0.0.1:6379> STRLEN k1 # 获取字符串长度
    (integer) 7
    127.0.0.1:6379> APPEND k1 "wz"
    (integer) 9
    127.0.0.1:6379> get k1
    "v1hellowz"
    
    
    1. 自增、自减、设置步长
    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> get views
    "1"
    127.0.0.1:6379> incr views
    (integer) 2
    127.0.0.1:6379> decr views # 自减1
    (integer) 1
    127.0.0.1:6379> get views
    "1"
    127.0.0.1:6379> decr views
    (integer) 0
    127.0.0.1:6379> get views
    "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 # 设置步长指定增量
    (integer) 9
    127.0.0.1:6379> get views
    "9"
    127.0.0.1:6379> DECRBY views 5 # 设置步长指定减量
    (integer) 4
    127.0.0.1:6379> get views
    "4"
    
    1. 字符串范围:截取与替换
    127.0.0.1:6379> set k1 "hello,warms"
    OK
    127.0.0.1:6379> get k1
    "hello,warms"
    127.0.0.1:6379> GETRANGE k1 0 3 # 截取字符串 [0,3]
    "hell"
    127.0.0.1:6379> GETRANGE k1 0 -1 #获取全部字符串
    "hello,warms"
    127.0.0.1:6379> set k2 abcdefg
    OK
    127.0.0.1:6379> get k2
    "abcdefg"
    127.0.0.1:6379> SETRANGE k2 1 xx # 替换指定位置开始的字符串
    (integer) 7
    127.0.0.1:6379> get k2
    "axxdefg"
    
    1. setex、setnx:设置过期时间,当前值不存在设置
    # setex (set with expire)
    # setnx (set if noy exist)在分布式锁中常常使用
    127.0.0.1:6379> setex k3 30 "hello" 
    OK
    127.0.0.1:6379> ttl k3
    (integer) 26
    127.0.0.1:6379> setnx mykey "redis" # 创建成功
    (integer) 1
    127.0.0.1:6379> keys *
    1) "k2"
    2) "mykey"
    3) "k1"
    127.0.0.1:6379> setnx mykey "mogodb" # 创建失败
    (integer) 0
    
    1. 设置、获取多个键值
    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 k2 v2 
    (integer) 0
    127.0.0.1:6379> msetnx k1 v1 k4 v4 # 原子性操作,要么一起成功要么一起失败
    (integer) 0
    
    1. 对象
    set user:1 {name:zhangsan, age:3} 设置一个user:1 对象 值为json字符来保存一个对象
    
    
    # 这里的key是一个巧妙地设计:user:{id}:{field} 例如文章浏览量:set article:1:views 0
    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"
    
    
    1. 组合命令 getset:先get 在set
    127.0.0.1:6379> getset db "redis" # 如果不存在值则返回null
    (nil)
    127.0.0.1:6379> get db
    "redis"
    127.0.0.1:6379> getset db "mogodb" # 如果存在值则获取原来的值并设置新的值
    "redis"
    127.0.0.1:6379> get db
    "mogodb"
    

    String类型使用场景:

    • 计数器
    • 统计多单位数量uid:123123:follow
    • 粉丝数
    • 对象缓存

    List


    基本数据类型,列表。
    在redis中可以将list用作栈、队列、阻塞队列!
    所有的list命令以 l l l开头

    1. 插入数据
    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"
    
    1. 移除数据
    127.0.0.1:6379> lrange list 0 -1
    1) "three"
    2) "two"
    3) "one"
    4) "right"
    127.0.0.1:6379> lpop list # 从左侧移除数据
    "three"
    127.0.0.1:6379> lrange list 0 -1
    1) "two"
    2) "one"
    3) "right"
    127.0.0.1:6379> rpop list # 从右侧移除数据
    "right"
    127.0.0.1:6379> lrange list 0 -1
    1) "two"
    2) "one"
    
    1. 通过下标获得某一个值
    127.0.0.1:6379> lrange list 0 -1
    1) "two"
    2) "one"
    127.0.0.1:6379> lindex list 1
    "one"
    127.0.0.1:6379> lindex list 0
    "two"
    127.0.0.1:6379> 
    
    1. list有多少元素
    127.0.0.1:6379> llen list
    (integer) 2
    
    1. 移除指定的值
    127.0.0.1:6379> lpush list three
    (integer) 3
    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 2 three
    (integer) 2
    127.0.0.1:6379> lrange list 0 -1
    1) "two"
    
    1. 只保留某一部分的元素
    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 "hello12"
    (integer) 3
    127.0.0.1:6379> rpush mylist "hello13"
    (integer) 4
    127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定长度,只保留截取的元素
    OK
    127.0.0.1:6379> lrange mylist 0 -1
    1) "hello1"
    2) "hello12"
    
    
    1. 组合操作rpoplpush
    27.0.0.1:6379> lrange mylist 0 -1
    1) "hello1"
    2) "hello12"
    127.0.0.1:6379> rpoplpush mylist mylist # 从尾部弹出,并从头部加入指定list
    "hello12"
    127.0.0.1:6379> lrange mylist 0 -1
    1) "hello12"
    2) "hello1"
    
    1. 更新list中的值
    127.0.0.1:6379> lpush list value1
    (integer) 1
    127.0.0.1:6379> lrange list 0 -1
    1) "value1"
    127.0.0.1:6379> lset list 0 item # 设置list下标为0的值为item
    OK
    127.0.0.1:6379> lrange list 0 -1
    1) "item"
    127.0.0.1:6379> lset list 1 a # 值不存在无法设置
    (error) ERR index out of range
    
    
    1. 插入操作
    127.0.0.1:6379> lpush mylist hello
    (integer) 1
    127.0.0.1:6379> lpush mylist world
    (integer) 2
    127.0.0.1:6379> lrange mylist 0 -1
    1) "world"
    2) "hello"
    127.0.0.1:6379> linsert mylist before world other # 在列表某个值前插入
    (integer) 3
    127.0.0.1:6379> lrange mylist 0 -1
    1) "other"
    2) "world"
    3) "hello"
    127.0.0.1:6379> linsert mylist after world new # 在列表某个值后插入
    (integer) 4
    127.0.0.1:6379> lrange mylist 0 -1
    1) "other"
    2) "world"
    3) "new"
    4) "hello"
    

    小结

    • list实际上是一个链表
    • 如果key不存在则创建新链表
    • 如果key存在则新增内容
    • 如果移除了所有值则代表空链表,也不存在
    • 可以作为消息队列、栈使用

    Set


    set中的值不能重复
    set命令以s开头

    1. 添加元素、查看元素、判断值是否存在
    127.0.0.1:6379> sadd myset hello # set集合中添加元素
    (integer) 1
    127.0.0.1:6379> smembers myset # 查看指定set的所有值
    1) "hello"
    127.0.0.1:6379> sismember myset hello  # 判断某个值是否在集合中
    (integer) 1
    
    
    1. 获取集合元素个数
    127.0.0.1:6379> scard myset
    (integer) 1
    
    1. 移除元素
    127.0.0.1:6379> sadd myset nihao
    (integer) 1
    127.0.0.1:6379> srem myset hello # 移除myset中的hello
    (integer) 1
    127.0.0.1:6379> smembers myset
    1) "nihao"
    
    
    1. set为无序不重复集合,可以抽随机
    127.0.0.1:6379> sadd myset v1
    (integer) 1
    127.0.0.1:6379> sadd myset v2
    (integer) 1
    127.0.0.1:6379> sadd myset v3
    (integer) 1
    127.0.0.1:6379> srandmember myset # 随机抽一个元素
    "nihao"
    127.0.0.1:6379> srandmember myset 
    "v2"
    127.0.0.1:6379> srandmember myset 2 # 随机抽选指定个数的元素
    1) "v1"
    2) "v2"
    
    1. 随机删除元素
    127.0.0.1:6379> smembers myset
    1) "v3"
    2) "v1"
    3) "v2"
    4) "nihao"
    127.0.0.1:6379> spop myset # 随机删除元素
    "v3"
    
    1. 将一个指定的值移动到另外一个set中
    127.0.0.1:6379> sadd myset hello
    (integer) 1
    127.0.0.1:6379> sadd myset world
    (integer) 1
    127.0.0.1:6379> sadd myset warms
    (integer) 1
    127.0.0.1:6379> sadd myset2 set2
    (integer) 1
    127.0.0.1:6379> smembers myset
    1) "hello"
    2) "warms"
    3) "world"
    127.0.0.1:6379> smembers myset2
    1) "set2"
    127.0.0.1:6379> smove myset myset2 warms # 将指定的值移动到另一个集合中
    (integer) 1
    127.0.0.1:6379> smembers myset2
    1) "warms"
    2) "set2"
    127.0.0.1:6379> smembers myset
    1) "hello"
    2) "world"
    
    1. 并集、差集、交集
    127.0.0.1:6379> sadd k1 a
    (integer) 1
    127.0.0.1:6379> sadd k1 b
    (integer) 1
    127.0.0.1:6379> sadd k1 c
    (integer) 1
    127.0.0.1:6379> sadd k2 c
    (integer) 1
    127.0.0.1:6379> sadd k2 d
    (integer) 1
    127.0.0.1:6379> sadd k2 e
    (integer) 1
    127.0.0.1:6379> sdiff k1 k2 # 差集
    1) "b"
    2) "a"
    127.0.0.1:6379> sinter k1 k2 # 交集 (共同好友可以这样实现)
    1) "c"
    127.0.0.1:6379> sunion k1 k2 # 并集
    1) "b"
    2) "c"
    3) "e"
    4) "a"
    5) "d"
    
    

    Hash


    Map集合, Key - Map,这时候的值为一个Map集合!本质和String类型没有太大区别,还是简单的Key-Value。
    所有的Hash命令以h开头

    1. 设置与获取
    127.0.0.1:6379> hset myhash field1 warms # 设置一个 key-value
    (integer) 1
    127.0.0.1:6379> hget myhash field1 # 获取1个字段值
    "warms"
    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"
    
    
    1. 删除字段
    127.0.0.1:6379> hdel myhash field1 # 删除hash指定的key字段
    (integer) 1
    127.0.0.1:6379> hgetall myhash
    1) "field2"
    2) "world"
    
    1. 获取hash中有几个键值对
    127.0.0.1:6379> hgetall myhash
    1) "field2"
    2) "world"
    3) "field1"
    4) "hello"
    127.0.0.1:6379> hlen myhash
    (integer) 2
    
    1. 判断某个字段是否存在
    127.0.0.1:6379> hexists myhash field1 # 判断hash中的指定字段是否存在
    (integer) 1
    
    1. 只获得所有的field、只获得所有的value
    127.0.0.1:6379> hkeys myhash # 只获得所有的field
    1) "field2"
    2) "field1"
    127.0.0.1:6379> hvals myhash # 只获得所有的value
    1) "world"
    2) "hello"
    
    1. 指定增量、如果不存在则可以设置
    127.0.0.1:6379> 
    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> hget myhash field3
    "6"
    127.0.0.1:6379> hincrby myhash field3 -1
    (integer) 5
    127.0.0.1:6379> hget myhash field3
    "5"
    127.0.0.1:6379> hsetnx myhash field4 hello
    (integer) 1
    127.0.0.1:6379> hsetnx myhash field4 hello
    (integer) 0
    

    hash应用:
    存储变更数据,尤其是用户信息的保存,以及经常变动的信息。hash更适合对象的存储,String更加适合字符串存储。

    Zset(有序集合)


    在set的基础上增加了一个值,
    set k1 v1
    zset k1 score1 v1
    Zset命令以z开头

    1. 设置与获取
    127.0.0.1:6379> zadd myset 1 one # 添加一个值
    (integer) 1
    127.0.0.1:6379> zadd myset 2 two
    (integer) 1
    127.0.0.1:6379> zrange myset 0 -1 # 获取所有值
    1) "one"
    2) "two"
    
    
    1. 实现排序
    127.0.0.1:6379> zadd salary 2500 xiaohong # 添加三个用户
    (integer) 1
    127.0.0.1:6379> zadd salary 5000 zhangsan
    (integer) 1
    127.0.0.1:6379> zadd salary 500 warms
    (integer) 1
    127.0.0.1:6379> zrange salary 0 -1
    1) "warms"
    2) "xiaohong"
    3) "zhangsan"
    127.0.0.1:6379> zrangebyscore salary -inf +inf # 递增显示全部用户
    1) "warms"
    2) "xiaohong"
    3) "zhangsan"
    127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 带score显示
    1) "warms"
    2) "500"
    3) "xiaohong"
    4) "2500"
    5) "zhangsan"
    6) "5000"
    127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores # 显示工资小于2500员工的升序排序
    1) "warms"
    2) "500"
    3) "xiaohong"
    4) "2500"
    127.0.0.1:6379> zrevrange salary 0 -1 # 降序排序
    1) "zhangsan"
    2) "warms"
    127.0.0.1:6379> zrevrange salary 0 -1 withscores
    1) "zhangsan"
    2) "5000"
    3) "warms"
    4) "500"
    
    
    1. 移除元素
    127.0.0.1:6379> zrange salary 0 -1
    1) "warms"
    2) "xiaohong"
    3) "zhangsan"
    127.0.0.1:6379> zrem salary xiaohong # 移除集合中的指定元素
    (integer) 1
    127.0.0.1:6379> zrange salary 0 -1
    1) "warms"
    2) "zhangsan"
    
    1. 查看元素数量
    127.0.0.1:6379> zcard salary # 获取有序集合中的个数
    (integer) 2
    
    1. 统计某区间内的成员数量
    127.0.0.1:6379> zcount salary 0 5000
    (integer) 2
    

    应用思路:

    • 班级成绩表、工资表
    • 带权重:普通消息、重要消息
    • 排行榜、top N 测试!

    三种特殊的数据类型

    geospatial(地理位置)


    应用:朋友定位、附近的人、打车距离计算

    可以查询一些测试数据:http://www.jsons.cn/lngcode/

    Geo底层为Zset实现

    1. geoadd添加地理位置
      规则:两极无法添加,我们一般会加载城市数据通过java程序一次性导入
      参数: key 值 (纬度、经度、名称)
    127.0.0.1:6379> geoadd china:city 116.40 39.90 beiging
    (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 106.50 29.53 chongqing
    (integer) 1
    127.0.0.1:6379> geoadd china:city 114.05 22.52 shengzheng
    (integer) 1
    127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
    (integer) 1
    127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
    (integer) 1
    
    1. 获取指定城市的精度和纬度
    127.0.0.1:6379> geopos china:city beiging
    1) 1) "116.39999896287918091"
       2) "39.90000009167092543"
    
    
    1. 计算两地距离

    单位

    • m 表示米
    • km 表示千米
    • mi 表示英里
    • ft 表示英尺
    # 单位默认为米
    127.0.0.1:6379> geodist china:city beiging shanghai
    "1067378.7564"
    127.0.0.1:6379> geodist china:city beiging shanghai km
    "1067.3788"
    
    1. 以给定的精度纬度为中心找出某一半径内的元素
    127.0.0.1:6379> georadius china:city 110 30 1000 km # 获取在以(100,30)为中心方圆1000km内的城市
    1) "chongqing"
    2) "xian"
    3) "shengzheng"
    4) "hangzhou"
    127.0.0.1:6379> georadius china:city 110 30 500 km
    1) "chongqing"
    2) "xian"
    
    1. 以一个元素为中心查找指定范围内的元素
    127.0.0.1:6379> georadiusbymember china:city beiging 1000 km
    1) "beiging"
    2) "xian"
    
    
    1. 返回一个位置或多个位置的Geohash表示
    # 将二维的经纬度转化为一维的字符串,如果两个字符串越接近,那么则距离越近
    127.0.0.1:6379> geohash china:city beiging
    1) "wx4fbxxfke0"
    
    1. 查询所有元素
    127.0.0.1:6379> zrange china:city 0 -1
    1) "chongqing"
    2) "xian"
    3) "shengzheng"
    4) "hangzhou"
    5) "shanghai"
    6) "beiging"
    
    
    1. 移除元素
    127.0.0.1:6379> zrem china:city beiging
    (integer) 1
    127.0.0.1:6379> zrange china:city 0 -1
    1) "chongqing"
    2) "xian"
    3) "shengzheng"
    4) "hangzhou"
    5) "shanghai"
    

    Hyperloglog

    什么是基数?
    A{1,3,5,7,8,7}
    B{1 , 3,5,7,8}
    基数(不重复的元素),可以接受误差

    Redis Hyperloglog 是用于基数统计的算法,该算法占用内存是固定的,2^64不同的元素的基数,只需要费12KB内存。存在0.81的错误率,统计UV的任务可以忽略不计。
    网页UV (一个人访问一个网站多次,但还是算作一个人)
    传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!这种方式保存了大量用户id,会很麻烦!

    1. 添加、统计、合并
    127.0.0.1:6379> pfadd mykey a b c d e f g h i j
    (integer) 1
    127.0.0.1:6379> pfcount mykey
    (integer) 10
    127.0.0.1:6379> pfadd mykey2 i j e a w k
    (integer) 1
    127.0.0.1:6379> pfcount mykey2
    (integer) 6
    127.0.0.1:6379> pfmerge mykey3 mykey mykey2
    OK
    127.0.0.1:6379> pfcount mykey3
    (integer) 12
    
    

    BitMap


    位存储
    统计用户信息,活跃,不活跃!登录、未登录!打卡!只有两个状态都可以使用Bitmap
    Bitmap 位图,数据结构!都是操作二进制位来记录,就只有0和1两个状态!

    1. 使用Bitmap记录打卡
    127.0.0.1:6379> setbit sign 0 1
    (integer) 0
    127.0.0.1:6379> setbit sign 2 0
    (integer) 0
    127.0.0.1:6379> setbit sign 1 0
    (integer) 0
    
    
    1. 查看某一天是否打卡
    127.0.0.1:6379> getbit sign 0
    (integer) 1
    127.0.0.1:6379> getbit sign 2
    (integer) 0
    
    1. 统计打卡天数
    127.0.0.1:6379> bitcount sign # 统计打卡天数就可以判断是否全勤
    (integer) 1
    
  • 相关阅读:
    071 Simplify Path 简化路径
    070 Climbing Stairs
    069 Sqrt(x) 求平方根
    067 Add Binary 二进制求和
    bzoj3295: [Cqoi2011]动态逆序对
    bzoj1598: [Usaco2008 Mar]牛跑步
    bzoj1492: [NOI2007]货币兑换Cash
    bzoj2683(要改一点代码)&&bzoj1176: [Balkan2007]Mokia
    bzoj2190: [SDOI2008]仪仗队
    bzoj3262: 陌上花开
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13859881.html
Copyright © 2020-2023  润新知