(三) Redis高级类型

Redis 列表 ( Lists )


     Redis的列表是使用链表实现的. 所以头部/尾部操作都是在常量时间完成.
     LPUSH/RPUSH 头尾增加
     
     Redis 采用链表来实现列表是因为,对于数据库系统来说,他们认为快速插入一个元素到一个很长的列表非常重要.另外一个即将描述的优势是, Redis列表能在常数时间内获得常数长度.
 
     如果需要快速访问一个拥有大量元素的集合的中间数据,可以用另一个称为有序集合的数据结构.

 

Redis 列表起步


 

      LPUSH/RPUSH 分别在头部/尾部添加一个元素到列表.

      LRANGE 从列表中提取一个范围内元素

     
     注意 LRANGE 命令使用两个索引下表,分别是返回的范围的开始和结束院所索引.两个索引坐标可以是负数,表示从后往前数,所以 -1 表示最后一个元素, -2 表示倒数第二个元素.以此类推.
     另:LPUSH/RPUSH 两个命令的参数都是可变长参数.

     

     LPOP/RPOP 分别在头部/尾部弹出一个元素 返回nil值表明列表中没有元素了.

     

 

列表的通用场景 ( Common use cases )


 

     具有列表代表性的场景如下:

          记录社交网络中用户最近提交的更新.
          可以模拟队列操作 ( 生产者消费者模式 ) 不过对于此项 Redis 有提供专用的列表命令来更可靠高效的解决该问题。

 

上限列表 ( Capped )


 

      Redis 允许使用列表作为一个上限集合,使用 LTRIM 命令仅仅记住最新的N项,丢弃掉所有老的项.

     LTRIM 命令类似于 LRANGE, 但是不同于展示指定范围的元素,而是将其作为列表新值存储.所有范围外的元素都将被删除.
     eg:
     
     LTRIM 所指定的范围是0到2 所以 数值 4 5 都被删除了.同时又返回了我们需要的数据.
     所以但要访问元素列表而又要抛弃老元素的时候,则可以使用 LTRIM 来操作
     注意:尽管LRANGE是一个 O ( N ) 时间复杂度的命令,访问列表头尾附近的小范围是常量时间的操作.

 

列表的阻塞操作 ( blocking )


 

     列表有一个特别的特性:阻塞操作.

     简单实现方式:
          生产者调用 LPUSH 添加项到列表中
          消费者调用 RPOP 从列表提取 / 处理项
 
     如果列表是空的 则RPOP返回NULL.所以消费者被签字等待一段时间并且重试 RPOP 命令.这称为轮询 ( polling ), 由于其具有一些缺点,所以不适合在如下情况中使用:
          1.强制 Redis 和客户端处理无用的命令 ( 但列表为空时,所有请求无实际操作 返回NULL ).
          2.由于工作者受到一个 NULL 后会等待一段时间,这会延迟对项的处理.
 
     介于以上的原因 Redis 实现了 BRPOP 和 BLPOP 两个命令,它们是但列表为空时 RPOP 和 LPOP 的会阻塞版本: 仅但一个新元素被添加到列表时, 或者到达了用户的指定超时时间, 才返回给调用者. 这个是我们在工作者中调用 BRPOP 的例子:
          消费者:
               
          生产者:
               
          brpop tasks 10 从tasks中弹出右边的数据 等待10秒
          lpush tasks 5 向tasks中压入数据5到左边
     注意: 这里可以使用0作为超时让其消费者一直等待元素,你也可以指定多个列表而不仅仅是一个,同时等待多个列表,但第一个列表收到元素后就能得到通知.
 
     关于BRPOP的一些注意事项
          1.客户端按顺序服务:第一个被阻塞等待列表的客户端,将第一个收到其他客户端添加的元素,等等.
          2.与 RPOP 的返回值不同: 返回的是一个数组,其中包括键的名字,因为 BRPOP 和 BLPOP 可以阻塞等待多个列表的元素.
          3.如果超时时间到达,返回 NULL
  
     还有更多需要知道的关于列表和阻塞的选项,可以具体阅读
          使用 RPOLPUSH 构建跟安全的队列和旋转队列.
          BRPOPLPUSH 命令是其阻塞命令的变种命令.

 

自动创建和删除键


     当一个列表为空时 Redis 将删除该键,但向一个不存在的列表键 ( 如使用 LPUSH ) 添加一个元素时,将创建一个空的列表.
     这并不只是针对列表,适用于所有 Redis 多元素组成的数据类型,因此适用于集合,有序集合和哈希.
     基本上我们可以概括为三条规则:
          1.但我们向聚合 ( aggregate ) 数据类型添加一个元素,如果键不存在,添加元素前就会自动创建一个空的聚合数据类型.
          2.但我们从聚合数据类型删除一个元素,如果值为空,则键也会被销毁.
          3.调用一个像 LLEN 的只读命令 ( 返回列表的长度 ),或者一个写命令从空键删除元素, 总是产生和操作一个持有空聚合类型值的键一样的结果.
 
     eg:
          规则1.
                    lpush foo 1 2 3 报错是因为 foo的数据类型是string 而我们用了列表操作lpush
          规则2.
                    如上图所示但所有元素弹出后,键就不存在了
          规则3.

 

Redis 哈希/散列 ( Hashes )


     Redis 哈希看起来正如你所期待的那样:
          
     哈希就是字段值对 ( fields-values pairs ) 的集合.由于哈希容易表示对象,事实上哈希中的字段的数量并没有限制,所以我们可以在应用程序以不同的方式来使用哈希.
 
     HMSET 命令为哈希设置多个字段, HGET 检索一个单独的字段. HMGET 类似于 HGET, 但是返回值是数组:
          
     也有一些命令可以针对单个字段执行操作, 例如 HINCRBY:
          
     你可以从命令页找到全部哈希命令列表.
     值得注意的是,小的哈希 ( 少量元素,不太大的值 ) 在内存中以一种特殊的方式编码以高效利用内存.

 

Redis 集合 (Sets)


     Redis 集合是无序的字符串集合 ( collections ). SADD 命令添加元素到集合.还可以对集合执行很多其他的操作,例如:测试元素是否存在,对多个集合执行交集/并集/和差集,等等.
     
     如上图给集合添加了 3 个元素,然后告诉 Redis 返回所有元素. 
     注:这里我用的MS维护的Redis客户端就自动排序了.其实他们是没有排序,Redis在每次调用时按随意顺序返回元素,因为没有与用户有任何元素排序协议.
 
     我们有测试成员关系的命令.一个指定的元素存在吗?
     
     " 3 " 是成员中的元素 反之 " 4 " 不是
 
     集合适用于表达对象间的关系.建模等~
 
     假设,我们想标记新闻.如果我们的 ID 为 1000 的新闻,被标签1, 2, 5 和 77标记,我们可以有一个这篇新闻被关联标记 ID 的集合:
     
     然后有时候我们也想要一些方向的关系 : 被某个标签标记的所有文章:
     
     获取指定对象的标签很简单:
     
     注意:在这个例子中,我们假设有另一个数据结构,例如,一个 Redis 哈希, 存储标签 ID 到标签名的映射.
 
     还有一些 Redis 命令很容易实现该操作.
     eg: 我们想获取所有被标签 1, 2, 10 和 27 同时标记的对象列表.
     我们可以使用 SINTER 命令实现这个, 也就是对不同的集合执行交集.
     
     并不仅仅是交集操作, 也可以执行并集,差集,随机抽取元素操作等等.
 
     抽取一个元素的命令是 SPOP, 就方便很多问题建模.
     eg:实现一个基于 web 的扑克游戏, 我可以将一副牌表示为集合.假设我们使用一个字符前缀表示(C)lubs 梅花, (D)iamonds 方块, (H)earts 红心, (S)pades 黑桃.
     
     现在我们要先copy一副牌数据,然后为每位选手提供5张牌.SPOP命令删除一个随机元素,返回给客户端,是在额个场景下的最佳操作.
     
     SUNIONSTORE 命令通常对多个集合执行交集,然后把结果存储在另外一个集合中.而对单个集合求交集就是其自身,于是:
     
     为第一个选手提供5张牌:
     
     好差的牌~ 哈
 
     SCARD 是提供集合中元素数量的命令.这个在集合理论中称为集合的基数 ( cardinality, 也称集合的势 ).
      
     OK 因为刚刚spop了5次 所以还剩47张牌 ( 元素 ).
     
     SRANDMEMBER 命令是提供获取随机元素的命令,只是他不会将获取到的元素从集合中删除.它具有返回重复元素和非重复元素的特性.

 

posted @ 2017-08-18 16:01  问号是我  阅读(270)  评论(0编辑  收藏  举报