zoukankan      html  css  js  c++  java
  • 【redis】-- redis的类型整理


    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)。

    redis的值没有类型,一般说redis的类型是指其key对应的value的值。value的类型一般分为五类, 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 下面来介绍一下这五种类型。

    1.字符串(String)

    string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型,一个键最大能存储512MB。

    在redis中字符串还可以分为3类,字符串,数值类型,及bitmap

    1.字符串

    应用场景:字符串的作用主要是用来存储数据。

    redis对字符串的操作命令主要有set、get、append、setrange、getrange、strlen。

    • set:将键key设定为指定的“字符串”值。如果 key 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。当set命令执行成功之后,之前设置的过期时间都将失效
    SET key value [EX seconds] [PX milliseconds] [NX|XX]
    
    • get:返回key的value。如果key不存在,返回特殊值nil。如果key的value不是string,就返回错误,因为GET只处理string类型的values
    GET key
    
    • append:如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作
    APPEND key value
    
    • setrange:这个命令的作用是覆盖key对应的string的一部分,从指定的offset处开始,覆盖value的长度。如果offset比当前key对应string还要长,那这个string后面就补0以达到offset。不存在的keys被认为是空字符串,所以这个命令可以确保key有一个足够大的字符串,能在offset处设置value。

    注意,offset最大可以是229-1(536870911),因为redis字符串限制在512M大小。如果你需要超过这个大小,你可以用多个keys。

    SETRANGE key offset value
    
    • getrange:这个命令是被改成GETRANGE的,在小于2.0的Redis版本中叫SUBSTR。 返回key对应的字符串value的子串,这个子串是由start和end位移决定的(两者都在string内)。可以用负的位移来表示从string尾部开始数的下标。所以-1就是最后一个字符,-2就是倒数第二个,以此类推。这个函数处理超出范围的请求时,都把结果限制在string内
    GETRANGE key start end
    

    2.数值

    应用场景:抢购,秒杀,详情页,点赞,评论。规避并发下,对数据库的事务操作完全由redis内存操作代替

    对数值进行操作的命令有incr

    • inrc:对存储在指定key的数值执行原子的加1操作。如果指定的key不存在,那么在执行incr操作之前,会先将它的值设定为0。如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)。这个操作仅限于64位的有符号整型数据。

    注意: 由于redis并没有一个明确的类型来表示整型数据,所以这个操作是一个字符串操作。执行这个操作的时候,key对应存储的字符串被解析为10进制的64位有符号整型数据。
    事实上,Redis 内部采用整数形式(Integer representation)来存储对应的整数值,所以对该类字符串值实际上是用整数保存,也就不存在存储整数的字符串表示(String representation)所带来的额外消耗。

    INCR key
    
    • incrby:将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
    INCRBY key increment
    
    • incrbyfloat:通过指定浮点数key来增长浮点数(存放于string中)的值. 当键不存在时,先将其值设为0再操作.下面任一情况都会返回错误:a.key 包含非法值(不是一个string).b.当前的key或者相加后的值不能解析为一个双精度的浮点值.(超出精度范围了)。如果操作命令成功, 相加后的值将替换原值存储在对应的键值上, 并以string的类型返回. string中已存的值或者相加参数可以任意选用指数符号,但相加计算的结果会以科学计数法的格式存储. 无论各计算的内部精度如何, 输出精度都固定为小数点后17位.
    INCRBYFLOAT key increment
    

    3.bitmap

    有关bitmap的操作有

    • setbit:设置或者清空key的value(字符串)在offset处的bit值。那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。当key不存在的时候,就创建一个新的字符串value。要确保这个字符串大到在offset处有bit值。参数offset需要大于等于0,并且小于232(限制bitmap大小为512)。当key对应的字符串增大的时候,新增的部分bit值都是设置为0。警告:当set最后一个bit(offset等于232-1)并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。在一台2010MacBook Pro上,offset为232-1(分配512MB)需要~300ms,offset为230-1(分配128MB)需要~80ms,offset为228-1(分配32MB)需要~30ms,offset为226-1(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETBIT就不会预先得到内存分配。
    SETBIT key offset value
    
    • getbit:返回key对应的string在offset处的bit值 当offset超出了字符串长度的时候,这个字符串就被假定为由0比特填充的连续空间。当key不存在的时候,它就认为是一个空字符串,所以offset总是超出范围,然后value也被认为是由0比特填充的连续空间。到内存分配
    GETBIT key offset
    
    • bitcount:统计字符串被设置为1的bit数.一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
    BITCOUNT key [start end]
    
    • bitop:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。

    BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数:
    BITOP AND destkey srckey1 srckey2 srckey3 … srckeyN ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
    BITOP OR destkey srckey1 srckey2 srckey3 … srckeyN,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
    BITOP XOR destkey srckey1 srckey2 srckey3 … srckeyN,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
    BITOP NOT destkey srckey,对给定 key 求逻辑非,并将结果保存到 destkey 。
    除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。
    执行结果将始终保持到destkey里面

    BITOP operation destkey key [key ...]
    
    • bitpos:返回字符串里面第一个被设置为1或者0的bit位。返回一个位置,把字符串当做一个从左到右的字节数组,第一个符合条件的在位置0,其次在位置8,等等。GETBIT 和 SETBIT 相似的也是操作字节位的命令。默认情况下整个字符串都会被检索一次,只有在指定start和end参数(指定start和end位是可行的),该范围被解释为一个字节的范围,而不是一系列的位。所以start=0 并且 end=2是指前三个字节范围内查找。注意,返回的位的位置始终是从0开始的,即使使用了start来指定了一个开始字节也是这样。和GETRANGE命令一样,start和end也可以包含负值,负值将从字符串的末尾开始计算,-1是字符串的最后一个字节,-2是倒数第二个,等等。不存在的key将会被当做空字符串来处理。
    BITPOS key bit [start] [end]
    

    案例:
    1,有用户系统,统计用户登录天数,且窗口随机

    setbit sean 1 1
    setbit sean 7 1
    setbit sean 364 1
    STRLEN sean
    BITCOUNT sean -2 -1
    

    4.其他

    string除过以上几种类型,还有几个通用的命令

    • setnx:将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。
    SETNX key value
    
    • mget:返回所有指定的key的value。对于每个不对应string或者不存在的key,都返回特殊值nil。正因为此,这个操作从来不会失败。
    MGET key [key ...]
    
    • mset:对应给定的keys到他们相应的values上。MSET会用新的value替换已经存在的value,就像普通的SET命令一样。如果你不想覆盖已经存在的values,请参看命令MSETNX。MSET是原子的,所以所有给定的keys是一次性set的。客户端不可能看到这种一部分keys被更新而另外的没有改变的情况。
    MSET key value [key value ...]
    
    • msetnx:对应给定的keys到他们相应的values上。只要有一个key已经存在,MSETNX一个操作都不会执行。 由于这种特性,MSETNX可以实现要么所有的操作都成功,要么一个都不执行,这样可以用来设置不同的key,来表示一个唯一的对象的不同字段。MSETNX是原子的,所以所有给定的keys是一次性set的。客户端不可能看到这种一部分keys被更新而另外的没有改变的情况
    MSETNX key value [key value ...]
    
    • setec:设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期。这个命令等效于执行下面的命令:***SET mykey value ; EXPIRE mykey seconds。***SETEX是原子的,也可以通过把上面两个命令放到MULTI/EXEC块中执行的方式重现。相比连续执行上面两个命令,它更快,因为当Redis当做缓存使用时,这个操作更加常用。
    SETEX key seconds value
    
    • psetec:PSETEX和SETEX一样,唯一的区别是到期时间以毫秒为单位,而不是秒。
    PSETEX key milliseconds value
    
    • strlen:返回key的string类型value的长度。如果key对应的非string类型,就返回错误。
    STRLEN key
    

    2.列表(list)

    就是链表数据结构,在redis中是一个双向的链表,并且每个节点都有其索引。可以把它当成数组,栈及队列使用。其数据结构的图示:

    图片

    主要使用的命令有:

    • lpush:将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。 所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
    LPUSH key value [value ...]
    
    • rpush:向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是一个列表,那么会返回一个错误。可以使用一个命令把多个元素打入队列,只需要在命令后面指定多个参数。元素是从左到右一个接一个从列表尾部插入。 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。
    RPUSH key value [value ...]
    
    • lpop:移除并且返回 key 对应的 list 的第一个元素。
    LPOP key
    
    • rpop:移除并返回存于 key 的 list 的最后一个元素。
    RPOP key
    
    • lpushs:只有当 key 已经存在并且存着一个 list 的时候,在这个 key 下面的 list 的头部插入 value。 与 LPUSH 相反,当 key 不存在的时候不会进行任何操作
    LPUSHX key value
    
    • lrang:返回存储在 key 的列表里指定范围内的元素。 start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。
    LRANGE key start stop
    
    • lindex:返回列表里的元素的索引 index 存储在 key 里面。 下标是从0开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。 负数索引用于指定从列表尾部开始索引的元素。在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。当 key 位置的值不是一个列表的时候,会返回一个error。
    LINDEX key index
    
    • lset:设置 index 位置的list元素的值为 value。 更多关于 index 参数的信息,详见 LINDEX。当index超出范围时会返回一个error。
    LSET key index value
    

    list可以用作单播,阻塞队列

    3.哈希(hash)

    是一个键值对集合。适合存储对象。

    主要的应用场景是:对field进行数值计算。点赞,收藏,详情页

    命令有:HDEL、HEXISTS、HGET、HGETALL、HINCRBY、HINCRBYFLOAT、HKEYS、HLEN、HMGET、HMSET、HSCAN、HSET、HSETNX、HSTRLEN、HVALS。

    • hset:设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。
    HSET key field value
    
    • hvals:返回 key 指定的哈希集中所有字段的值。
    HVALS key
    
    • hmset:设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联
    HMSET key field value [field value ...]
    

    其实hash的命令没什么好说的,就是在普通的get,set等命令前加上h用来标识是对hash的操作。故这里只列出几个常用的命令的意思。

    4.集合(set)

    set是一个【无序】&&【随机性】的列表。放入的多少不同,元素存储的顺序不同。会对放入数据的相同数据进行去重。有着丰富的集合操作。还可取随机值。

    其命令有:SADD、SCARD、SDIFF、SDIFFSTORE、SINTER、SINTERSTORE、ISMEMBER、SMEMBERS、SMOVE、SPOP、SRANDMEMBER、SREM、SSCAN、SUNION、SUNIONSTORE。

    这里对添加等命令不过多解释,和hash一样就是以s开头作为set类型的标识。

    • sdiff:返回一个集合与给定集合的差集的元素.
    SDIFF key [key ...]
    
    • sdiffstore:该命令类似于 SDIFF, 不同之处在于该命令不返回结果集,而是将结果存放在destination集合中.如果destination已经存在, 则将其覆盖重写.
    SDIFFSTORE destination key [key ...]
    
    • sinter:返回指定所有的集合的成员的交集.
    SINTER key [key ...]
    
    • sinterstore:这个命令与SINTER命令类似, 但是它并不是直接返回结果集,而是将结果保存在 destination集合中.如果destination 集合存在, 则会被重写.
    SINTERSTORE destination key [key ...]
    
    • srangember:仅提供key参数,那么随机返回key集合中的一个元素.Redis 2.6开始,可以接受 count 参数,如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,当count是负数,则会返回一个包含count的绝对值的个数元素的数组,如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
    SRANDMEMBER key [count]
    
    • sunion:返回给定的多个集合的并集中的所有成员.
    SUNION key [key ...]
    
    • sunionstore:该命令作用类似于SUNION命令,不同的是它并不返回结果集,而是将结果存储在destination集合中.如果destination 已经存在,则将其覆盖.
    SUNIONSTORE destination key [key ...]
    

    5.有序集合(sorted sets)

    和Sets相比,Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,其物理内存左小右大不随命令发生变化。与set一样有对集合的操作。而redis中的跳跃表也是使用了有序集合类型。

    有序列表的命令,太多且都很重要所以可以参考http://redis.cn/commands/bzpopmax.html

    跳跃表

    跳跃表(skiplist)是一种随机化的数据, 由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出, 跳跃表以有序的方式在层次化的链表中保存元素, 效率和平衡树媲美 —— 查找、删除、添加等操作都可以在对数期望时间下完成, 并且比起平衡树来说, 跳跃表的实现要简单直观得多。

    以下是个典型的跳跃表例子(图片来自维基百科):

    图片

    从图中可以看到, 跳跃表主要由以下部分构成:

    表头(head):负责维护跳跃表的节点指针。

    跳跃表节点:保存着元素值,以及多个层。

    层:保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针,为了提高查找的效率,程序总是从高层先开始访问,然后随着元素值范围的缩小,慢慢降低层次。

    表尾:全部由 NULL 组成,表示跳跃表的末尾。

    这里只做简单介绍详细内容可以查看以下链接:

    https://redisbook.readthedocs.io/en/latest/internal-datastruct/skiplist.html

  • 相关阅读:
    Python进程池multiprocessing.Pool的用法
    基于opencv的车牌提取项目
    Srapy 爬取知乎用户信息
    Scrapy框架简介及小项目应用
    豆瓣爬取图书标签
    CSS选择器使用
    关于 urlencode 的使用和 json 模块的介绍
    urllib库使用方法
    猫眼电影的各种爬取方法
    淘宝商品信息爬取
  • 原文地址:https://www.cnblogs.com/wf614/p/12919819.html
Copyright © 2011-2022 走看看