1. 集合类型

  集合类型与列表类型有很多相似之处,但二者的区别在于:前者具有唯一性,但不具有有序性;后者具有有序性,但不具有唯一性。集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,以及多个集合类型之间进行并集、交集和差集运算。

  (1) 命令

  1) 增加/删除元素

  格式为:SADD key member [member ...]    SREM key member [member ...]

  SADD向集合中增加一个或多个元素,加入的元素若已存在语集合中,则会忽略该元素。命令返回成功加入的元素数量(忽略不计算在内)。SREM命令用于从集合中删除一个或多个元素,并返回删除成功的个数。

127.0.0.1:[]> SADD letters a
(integer)
127.0.0.1:[]> SADD letters a b c
(integer) 127.0.0.1:[]> TYPE letters
set
# 由于"d"在集合中不存在,所以只删除了一个元素,返回值为1
127.0.0.1:[]> SREM letters c d
(integer)

  2) 获得集合中所有元素

  格式为:SMEMBERS key

127.0.0.1:[]> SMEMBERS letters
) "b"
) "a"

  3) 判断元素是否在集合中

  格式为:SISMEMBER key member,该命令的时间复杂度为O(1),值存在时返回1,否则返回0。

127.0.0.1:[]> SISMEMBER letters a
(integer)
127.0.0.1:[]> SISMEMBER letters d
(integer)

  4) 集合间运算

  格式为:SDIFF key (key ...)    SINTER key (key ...)    SUNION key (key ...)

  SDIFF是对多个集合执行差集运算,如{1,2,3} - {2,3,4} = {1},{2,3,4} - {1,2,3} = {4}

127.0.0.1:[]> SADD set1
(integer)
127.0.0.1:[]> SADD set2
(integer)
127.0.0.1:[]> SDIFF set1 set2
) ""
127.0.0.1:[]> SDIFF set2 set1
) "" # SDIFF支持同时传入多个键,顺序为先计算set1-set2,再计算结果与set3的差集
127.0.0.1:[]> sadd set3
(integer)
127.0.0.1:[]> sdiff set1 set2 set3
) ""

  SINTER命令用来对多个集合执行交集运算,如{1,2,3} & {2,3,4} = {2,3}

127.0.0.1:[]> SDIFF set1 set2 set3
) ""
127.0.0.1:[]> SINTER set1 set2 set3
) ""
) ""

  SUNION用来对多个集合执行并集运算,如{1,2,3} or {2,3,4} = {1,2,3,4}.

127.0.0.1:[]> SUNION set1 set2 set3
) ""
) ""
) ""
) ""

  5) 获取集合中元素的个数

  格式为:SCARD key

127.0.0.1:[]> SMEMBERS set2
) ""
) ""
) ""
127.0.0.1:[]> SCARD set2
(integer)

  6) 进行集合运算并将结果存储

   格式为:SDIFFSTORE destionation key [key...]  SINTERSTORE destination key [key ...]   SUNIONSTORE destination key [key ...]

127.0.0.1:[]> SDIFFSTORE result set1 set2
(integer)
127.0.0.1:[]> get reult
(nil)
127.0.0.1:[]> SMEMBERS result
) ""
127.0.0.1:[]> TYPE result
set

  7) 随机获得集合中的元素

  格式为:SRANDMEMBER key [count],count表示一次获取多个元素,当count为正数,SRANDMEMBER会随机从集合中获得count个不重复的元素,如果count的值大于集合中的元素个数,SRANDMEMBER会返回集合中的全部元素;如果count为负数,SRANDMEMBER会随机从集合中获得|count|个元素,且这些元素有可能相同。

127.0.0.1:[]> SRANDMEMBER set1
""
127.0.0.1:[]> SRANDMEMBER set1
""
127.0.0.1:[]>
127.0.0.1:[]> SADD letters a b c d
(integer)
127.0.0.1:[]> SRANDMEMBER letters
) "d"
) "a"
127.0.0.1:[]> SRANDMEMBER letters
) "d"
) "a"
) "b"
) "c"
127.0.0.1:[]> SRANDMEMBER letters -
) "d"
) "d"
127.0.0.1:[]> SRANDMEMBER letters -
) "a"
) "a"
) "a"
) "d"
) "d"
) "d"
) "c"
) "b"
) "d"
) "d"

  8) 从集合中弹出一个元素

  格式为:SPOP key,LPOP是从列表左边弹出一个元素,但集合类型的元素是无序的,SPOP会从集合中随机选择一个元素弹出。

127.0.0.1:[]> SPOP letters
"d"
127.0.0.1:[]> SMEMBERS letters
) "c"
) "b"
) "a"

  (2) 示例

  1) 存储文章标签:一个文章的所有标签互补相同,且对标签排序不要求,对每篇文章使用键为"post:文章ID:tags"的键存储文章标签,伪代码:

# ID为42的文章添加标签
SADD post::tags 闲言碎语,技术文章, Java # 删除标签
SREM post::tags, 闲言碎语 # 显示所有标签
$tags = SMEMBERS post::tags
print $tags

  注意:使用集合类型键存储标签适合需要单独增加或删除标签的场合。其次,有些地方需要用户直接设置所有标签后一起上传。

  2) 通过标签搜索文章

  列出某个标签下的所有文章,甚至获得同时属于几个标签的文章列表,为每个标签使用一个"tags:标签名称:posts"的集合类型存储标有该标签的文章ID列表。当需要获取"MySQL"标签的文章时只需要使用命令SMEMBERS tags:MYSQL:posts;当同时找出属于Java、MYSQL、Redis三个标签的文章,只需要将tag:java:posts、tags:MYSQL:posts和tags:Redis:posts这3个键取交集,借助SINTER命令。

2. 有序集合类型

  有序集合类型为集合中的每一个元素都关联了一个分数,不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作,并且元素的分数可以相同。

  有序集合与列表的区别:

  1) 列表通过链表实现,获取靠近两端的数据速度极快,二访问中间数据的速度会较慢,适合实现"新鲜事"或"日志"这样很少访问中间元素的应用。

  2) 有序集合是使用散列表和跳跃表(skip list)实现的,所以即使读取位于中间部分的数据速度也很快。  

  3) 列表中不能简单地调整某个元素的位置,但有序集合可以(通过改变元素的分数)。

  4) 有序集合要比列表类型更耗费内存。

  (1) 命令

  1)  增加元素

  格式为:ZADD key score member [score member ...]

  ZADD用于向有序集合加入一个元素和该元素的分数,若已存在,则会使用新的分数替换原有的分数,返回新加入集合中的元素个数。

# 记录三个人的分数
127.0.0.1:> ZADD scoreboard Tom Peter David
(integer)
# 修改Peter的分数
127.0.0.1:> ZADD scoreboard Peter
(integer) # 分数不仅可以是整数,还支持double类型
127.0.0.1:> ZADD testboard 17E+ a
(integer)
127.0.0.1:> ZADD testboard 1.5 b
(integer)
127.0.0.1:> ZADD testboard +inf c #正无穷
(integer)
127.0.0.1:> ZADD testboard -inf d #负无穷
(integer)

  2) 获得元素的分数

  格式为: ZSCORE key member

127.0.0.1:> ZSCORE scoreboard Peter
""

  3) 获得排名在某个范围的元素列表

  格式为:ZRANGE key start stop [WITHSCORES]    ZREVRANGE key start stop [WITHSCORE]

  ZRANGE会按元素分数从小到大顺序返回索引从start到stop之间的所有元素(包含两端的元素),同时获得元素的分数可以加上WITHSCORES参数。ZRANGE索引从0开始,负数代表从后向前查找(-1表示最后一个元素);ZREVRANG会按照元素分数从大到小的顺序给出结果。

127.0.0.1:> ZRANGE scoreboard
) "Peter"
) "Tom"
) "David"
127.0.0.1:> ZRANGE scoreboard -
) "Tom"
) "David" 127.0.0.1:> ZRANGE scoreboard - WITHSCORES
) "Peter"
) ""
) "Tom"
) ""
) "David"
) ""

  如果两个元素的分数相同,Redis会按照字典顺序(0<9<A<Z<a<z)来进行排序,再进一步,如果元素的值是中文,则取决于中文的编码方式。

# 分数相同情况
127.0.0.1:> ZRANGE scoreboard - WITHSCORES
) "Peter"
) ""
) "Tom"
) ""
) "David"
) ""
) "Oliver"
) "" # 中文情况
127.0.0.1:> ZADD chineseName 马华 黎明 姚明 李娜
(integer)
127.0.0.1:> ZRANGE chineseName - WITHSCORES
) "\xe5\xa7\x9a\xe6\x98\x8e"
) ""
) "\xe6\x9d\x8e\xe5\xa8\x9c"
) ""
) "\xe9\xa9\xac\xe5\x8d\x8e"
) ""
) "\xe9\xbb\x8e\xe6\x98\x8e"
) ""

  4) 获得指定分数范围的元素

  格式为:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

  该命令按照元素大从小到大返回分数在min和max之间的元素。如果希望分数不包含端点值,可以在分数前加上"("符号,如获取80到100分的数据,包含80,不包含100。

  LIMIT offset count时在获得的元素列表的基础上向后偏移offset个元素,并且只获取前count个元素。

# 获取分数在[,]间的元素
127.0.0.1:> ZRANGEBYSCORE scoreboard
) "Tom"
) "David"
) "Oliver" # 获取分数在[,)之间的元素,包含80,不包含100的元素
127.0.0.1:> ZRANGEBYSCORE scoreboard (
) "Tom" # 获取分数在(,+inf]之间的元素,即大于80的元素
127.0.0.1:> ZRANGEBYSCORE scoreboard ( +inf
) "Tom"
) "David"
) "Oliver" # scoreboard的元素以及分数
127.0.0.1:> ZRANGE scoreboard - WITHSCORES
) "Peter"
) ""
) "Tom"
) ""
) "David"
) ""
) "Oliver"
) "" # 获取分数高于80分的从第二个人开始的2个人
127.0.0.1:> ZRANGEBYSCORE scoreboard +inf WITHSCORES LIMIT
) "David"
) ""
) "Oliver"
) "" # 获取分数低于100的前2个人
127.0.0.1:> ZREVRANGEBYSCORE scoreboard ( WITHSCORES LIMIT
) "Tom"
) ""
) "Peter"
) ""

  5) 增加某个元素的分数

  格式为:ZINCRBY key increment member

  ZINCRBY可以增加一个元素的分数(正数和负数均可),返回值是更改后的分数。如果指定元素不存在,Redis会先建立它并将它的分数赋为0再执行操作。

127.0.0.1:6379> ZRANGE scoreboard 0 -1 WITHSCORES
1) "Peter"
2) "76"
3) "Tom"
4) "89"
5) "David"
6) "100"
7) "Oliver"
8) "100"
# 将Tom的分数减少5分
127.0.0.1:6379> ZINCRBY scoreboard -5 Tom
"84"

  6) 获得集合中的元素数量

  格式为:ZCRAD key

127.0.0.1:> ZCARD scoreboard
(integer)

  7) 获得指定分数范围的元素个数

  格式为:ZCOUNT key min max

127.0.0.1:> ZCOUNT scoreboard (80 +inf
(integer)

  8) 删除一个或多个元素

  ZREM key member [member ...]

127.0.0.1:> ZREM scoreboard Oliver
(integer)
127.0.0.1:> ZCARD scoreboard
(integer)

  9) 按照排名范围删除元素

  ZREMRANGEBYRANK key start stop

  该命令按照元素分数从大到小的顺序删除指定排名范围内的所有元素,并返回删除的元素数量。

127.0.0.1:> ZADD testRem  a  b  c  d  e  f
(integer)
127.0.0.1:> ZREMRANGEBYRANK testRem
(integer)
127.0.0.1:> ZRANGE testRem - WITHSCORES
) "d"
) ""
) "e"
) ""
) "f"
) ""

  10) 按照分数范围删除元素

  格式为:ZREMRANGEBYSCORE key min max

  该命令会删除指定分数范围内的所有元素,返回值是删除的元素数量。

127.0.0.1:> ZREMRANGEBYSCORE testRem (
(integer)
127.0.0.1:> ZRANGE testRem - WITHSCORES
) "d"
) ""
) "f"
) ""

  11) 获得元素的排名

  格式为:ZRANK key member    ZREVRANK key member

  ZRANK会按照分数从小到大的顺序获得指定的元素排名。ZREVRANK命令则相反。

# 从小到大的顺序获取Peter的排名
127.0.0.1:> ZADD scoreboard Peter Tom Green William
(integer)
127.0.0.1:> ZRANK scoreboard Peter
(integer) # 从大到小的顺序获取其排序
127.0.0.1:> ZREVRANK scoreboard Peter
(integer)

  12) 计算有序集合的交集

  格式为:ZINTERSTORE destination numkeys key [key ...] [WEIGHT weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

  该命令用来计算多个有序集合的交集并将结果存储在destination中,返回值为destination的个数,destination键中元素的分数是由AGGREGATE参数决定的。

  a. 当AGGREGATE是SUM时(默认),destination键中元素的分数是每个参与计算的集合中该元素的分数的和。

127.0.0.1:> ZADD sortedSets1  a  b
(integer)
127.0.0.1:> ZADD sortedSets2 a b
(integer)
127.0.0.1:> ZINTERSTORE sortedSetsResult sortedSets1 sortedSets2
(integer)
127.0.0.1:> ZRANGE sortedSetsResult - WITHSCORES
) "a"
) ""
) "b"
) ""

  b. 当AGGREGATE是MIN时。destination键中元素的分数是每个参与计算的集合中该元素分数的最小值。

127.0.0.1:> ZINTERSTORE sortedSetResult  sortedSets1 sortedSets2 AGGREGATE MIN
(integer)
127.0.0.1:> ZRANGE sortedSetResult - WITHSCORES
) "a"
) ""
) "b"
) ""

  c. 当AGGREGATE是MAX时,destination键中元素的分数是每个参与计算的集合中该元素的最大值。

127.0.0.1:> ZINTERSTORE sortedSetResult  sortedSets1 sortedSets2 AGGREGATE MAX
(integer)
127.0.0.1:> ZRANGE sortedSetResult - WITHSCORES
) "a"
) ""
) "b"
) ""

  ZINTERSTORE命令还能够通过WEIGHTS参数设置每个集合的权重,每个集合在参与计算时元素的分数会被乘上该集合的权重。

127.0.0.1:> ZINTERSTORE sortedSetResult  sortedSets1 sortedSets2 WEIGHTS  0.1
(integer)
127.0.0.1:> ZRANGE sortedSetResult - WITHSCORES
) "a"
) ""
) "b"
) ""

  13) 计算集合间的并集

  与ZINTERSTORE命令用法一样

  (2) 示例

  1) 实现按点击量排序

  有序集合的键以文章ID作为元素,以该文章的点击量作为该元素的分数。该键命名为posts:page.view,每次用户访问一篇文章,则通过"ZINCRBY posts:page.view 1 文章ID"。  

  按点击量的顺序显示文章列表:

$postsPerPage=
$start = ($currentPage - ) * $postsPerPage
$end = $currentPage * $postsPerPage -
$postsId = ZREVRANGE posts:page.view, $start, $end for each $id in $postsID
$postData = HGETALL post:$id
print 文章标题: $postData.title

  获得某篇文章的访问量可通过:ZSCORE posts:page.view 文章ID来实现。

  2) 改进按时间排序

  为了能自由地更改文章发布时间,可采用有序集合类型替代列表类型,元素仍为文章ID,此时元素的分数是文章发布的LInux时间,可以修改元素对应的分数就可以达到更改时间的目的。

  借助ZREVRANGEBYSCORE命令还可以轻松获得指定时间范围的文章列表,借助这个功能可以实现类似WordPress的按月份查看文章的功能。

Redis学习笔记(3) Redis基础类型及命令之二的更多相关文章

  1. Redis学习笔记(1) Redis介绍及基础

    1. Redis的特性 (1) 存储结构 Redis(Remote Dictionary Server,远程字典服务器)是以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容.Redis支 ...

  2. redis学习笔记之redis简介

    redis简介 Redis是一个开源的,高性能的,基于键值对的缓存与存储系统,通过设置各种键值数据类型来适应不同场景下的缓存与存储需求.同事redis的诸多高层级功能使其可以胜任消息队列,任务队列等不 ...

  3. Redis学习笔记(4) Redis事务、生存时间及排序

    1. Redis事务 Redis中的事务(transaction)是一组命令的集合,一个事务中的命令要么都执行,要么都不执行.事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次 ...

  4. Redis学习笔记之Redis单机,伪集群,Sentinel主从复制的安装和配置

    0x00 Redis简介 Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值 ...

  5. StackExchange.Redis学习笔记(一) Redis的使用初探

    Redis Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化. 与其它键值数据存储相比,Redis有一组相对丰富的数据类型. Redis可以将数据复制到任意数量的从机中 Redis的安装 官 ...

  6. Redis学习笔记(2) Redis基础类型及命令之一

    1. 基础命令 (1) 获取符合规则的键名列表 格式为:KEYS pattern 其中pattern表示支持通配符 # 建立一个名为bar的键 > SET bar OK # 获取Redis所有键 ...

  7. Redis学习笔记之入门基础知识——其他特性

    1.订阅(subscribe)与发布(publish) 用户订阅某一个频道,频道发布新的信息时,会将信息告知用户 2.数据安全 1)     快照持久化(时间点转储,实质是数据副本) 操作:SAVA. ...

  8. Redis学习笔记(一):基础数据结构

    一. 引言 <Redis设计与实现>一书主要分为四个部分,其中第一个部分主要讲的是Redis的底层数据结构与对象的相关知识. Redis是一种基于C语言编写的非关系型数据库,它的五种基本对 ...

  9. Redis学习笔记之入门基础知识——五种数据类型

    1) 字符串 SET设置值,GET获取值,DEL删除值 INCR key-name将键存储的值加上1       DECR key-name将键存储的值减去1 INCRBY key-name amou ...

随机推荐

  1. BZOJ3172: [Tjoi2013]单词

    传送门 做了这么多题怎么还是无法很好的理解AC自动机呢..果然是个制杖 首先题意表述不是很清晰,这些所有的单词组成了那个文章,所以果断建个AC自动机,建的时候给每个点附加一个权值,建树是经过一次权值即 ...

  2. 简要介绍BASE64、MD5、SHA、HMAC几种方法。

    加密解密,曾经是我一个毕业设计的重要组件.在工作了多年以后回想当时那个加密.解密算法,实在是太单纯了.     言归正传,这里我们主要描述Java已经实现的一些加密解密算法,最后介绍数字证书.     ...

  3. QQ等级表

    什么是QQ等级呢? 2003年,腾讯公司推出了QQ等级制度 . 最早是以小时,来计算的,那段时间,绝大部分QQ用户都在挂QQ,之后就有不少媒体指责其浪费能源,在有关部门的介入下,腾讯公司将QQ等级变为 ...

  4. The RAII Programming Idiom

    https://www.hackcraft.net/raii/ https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

  5. 清北学堂模拟赛day7 石子合并加强版

    /* 注意到合并三堆需要枚举两个端点,其实可以开一个数组记录合并两堆的结果,标程好像用了一个神奇的优化 */ #include<iostream> #include<cstdio&g ...

  6. easyui-textbox回车事件

    $('#id').textbox('textbox').keydown(function (e) { if (e.keyCode == 13) { alert('enter'); } });

  7. nyoj 106背包问题(贪心专题)

    背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w< ...

  8. jQuery如何判断元素是否是隐藏的?

    jQuery函数简介: is(expr) 用一个表达式来检查当前选择的元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true. 如果没有元素符合,或者表达式无效,都返回'false'. 注 ...

  9. shell--2.shell数组

    shell 数组 (1)定义数组 shell中,用括号表示数组,数组元素用空格分开,定义数组的一般形式 arrt_name=(val1 val2 val3) 或者 arry_name=(val1 va ...

  10. css如何实现水平居中呢?css实现水平居中的方法?

    面试中遇到的一个问题:如何让css实现水平居中?下面来看一下哪些方法能实现水平居中. 首先分两种情况,行内元素还是块级元素.然而块级元素又分为定宽块状元素和不定款块状元素.先来看下行内元素如何水平居中 ...