字符串 P39

Redis 的字符串是一个有字节组成的序列,可以存储以下 3 种类型的值:字节串(byte string)、整数、浮点数。

在需要的时候, Redis 会将整数转换成浮点数。整数的取值范围和系统的长整型(long)的相同,浮点数取值范围和精度与 IEEE 754 标准下的双精度浮点数(double)的相同。

Redis 中的自增命令和自减命令 P39

命令

格式

描述

INCR

INCR key

将键存储的数字值加上 1

DECR

DECR key

将键存储的数字值减去 1

INCRBY

INCRBY key increment

将键存储的数字值加上整数增量 increment

DECRBY

DECRBY key decrement

将键存储的数字值减去整数减量 decrement

INCRBYFLOAT

INCRBYFLOAT key increment

将键存储的数字值加上浮点数增量 increment

相关演示代码如下(mainhandleResult 定义见:01. Redis 数据结构简介):

// 执行字符串类型数字相关操作
func executeNumberOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "number")))
	// 获取值,输出 -> ERROR:  redigo: nil returned
	handleResult(redis.Int(conn.Do("GET", "number")))
	// 自增 1,返回自增后的值 -> 1
	handleResult(redis.Int(conn.Do("INCR", "number")))
	// 自增 2,返回自增后的值 -> 3
	handleResult(redis.Int(conn.Do("INCRBY", "number", "2")))
	// 自减 1,返回自减后的值 -> 2
	handleResult(redis.Int(conn.Do("DECR", "number")))
	// 自减 2,返回自减后的值 -> 0
	handleResult(redis.Int(conn.Do("DECRBY", "number", "2")))
	// 自增 1.5,返回自增后的值 -> 1.5
	handleResult(redis.Float64(conn.Do("INCRBYFLOAT", "number", "1.5")))
	// 自增 -1.3,返回自增后的值 -> 0.2
	handleResult(redis.Float64(conn.Do("INCRBYFLOAT", "number", "-1.3")))
}
供 Redis 处理子串和二进制位的命令 P40

命令

格式

描述

APPEND

APPEND key value

将 value 追加到 key 当前值的末尾

GETRANGE

GETRANGE key start end

返回 [start, end] 范围内子串

SETRANGE

SETRANGE key offset value

将子串 [offset, offset + len(value)) 设置为 value

GETBIT

GETBIT key offset

将字符串看作是二进制位串,获取 offset 上的位

SETBIT

SETBIT key offset value

将字符串看作是二进制位串,设置 offset 上的位为 value

BITCOUNT

BITCOUNT key [start end]

统计 [start, end] 范围内子串在二进制下有多少个 1

BITOP

BITOP operation destkey key [key ...]

operation 可选位运算 AND , OR , XOR , NOT ,将一个或多个二进制位串执行的操作结果存到 destkey 中

相关演示代码如下:

// 执行字符串类型字符串相关操作
func executeStringOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "string")))
	// 追加串,返回当前字符串长度 -> 6,值变为 -> append
	handleResult(redis.Int(conn.Do("APPEND", "string", "append")))
	// 获取子串,返回 -> en
	handleResult(redis.String(conn.Do("GETRANGE", "string", 3, 4)))
	// 设置子串,返回当前字符串长度 -> 6,值变为 -> appled
	handleResult(redis.Int(conn.Do("SETRANGE", "string", 3, "le")))
	// 设置子串,返回当前字符串长度 -> 11,值变为 -> application
	handleResult(redis.Int(conn.Do("SETRANGE", "string", 3, "lication")))
	// 获取二进制位,返回 -> 1
	// (获取第 7/8 个字符 a 在二进制下第 7%8 位上的二进制位,即 0110 0001 的第 7 位 1)
	handleResult(redis.Int(conn.Do("GETBIT", "string", 7)))
	// 设置二进制位,返回原来的二进制位 -> 0,值变为 -> cpplication
	// (设置第 6/8 个字符 a 在二进制下第 6%8 位上的二进制位为1,即 0110 0001 变为 0110 0011)
	handleResult(redis.Int(conn.Do("SETBIT", "string", 6, 1)))
	// 统计二进制位,返回 -> 7
	// (统计 [0, 1] 范围内子串 cp 在二进制下 0110 0011 0111 0000 二进制位为 1 的数量)
	handleResult(redis.Int(conn.Do("BITCOUNT", "string", 0, 1)))

	handleResult(redis.String(conn.Do("SET", "aKey", "aa")))
	handleResult(redis.String(conn.Do("SET", "bKey", "b")))
	// 对 aa(0110 0001 0110 0001) 和 b(0110 0010 0000 0000) 进行 按位或,结果存储到 cKey 中
	// 返回字符串长度 -> 2,值为 ca(0110 0011 0110 0001),
	handleResult(redis.Int(conn.Do("BITOP", "OR", "cKey", "aKey", "bKey")))
}

Redis 可以通过使用子串操作和二进制位操作,配合 WATCHMULTIEXEC 命令(后面会初步介绍,以后将深入讲解),构建任何想要的数据结构。

列表 P42

一些常用的列表命令 P42

命令

格式

描述

RPUSH

RPUSH key value [value ...]

依次将一个或多个 value 从列表右端插入

LPUSH

LPUSH key value [value ...]

依次将一个或多个 value 从列表左端插入

RPOP

RPOP key

移除并返回列表最右端的元素

LPOP

LPOP key

移除并返回列表最左端的元素

LINDEX

LINDEX key offset

返回列表左端开始偏移量为 offset 的元素

LRANGE

LRANGE key start end

返回列表左端开始 [start, end] 范围内的所有元素

LTRIM

LTRIM key start end

移除列表左端开始 [start, end] 范围外的所有元素

相关演示代码如下:

// 执行列表类型相关操作
func executeListOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "list")))
	// 右端插入一次插入 a, b, c,返回当前列表长度 -> 3,列表变为 -> a b c
	handleResult(redis.Int(conn.Do("RPUSH", "list", "a", "b", "c")))
	// 左端插入一次插入 d, e, f,返回当前列表长度 -> 6,列表变为 -> f e d a b c
	handleResult(redis.Int(conn.Do("LPUSH", "list", "d", "e", "f")))
	// 弹出并返回列表最右端的值,返回 -> c,列表变为 -> f e d a b
	handleResult(redis.String(conn.Do("RPOP", "list")))
	// 弹出并返回列表最左端的值,返回 -> f,列表变为 -> e d a b
	handleResult(redis.String(conn.Do("LPOP", "list")))
	// 返回左端开始下标偏移量为 offset 的值,返回 -> d
	handleResult(redis.String(conn.Do("LINDEX", "list", 1)))
	// 移除列表左端开始 [1, 2] 范围外的所有元素,列表变为 -> d a
	handleResult(redis.String(conn.Do("LTRIM", "list", 1, 2)))
}

利用 LTRIM 命令可以原子地弹出多个元素。 P43

阻塞式的列表弹出命令以及在列表之间移动元素的命令 P43

命令

格式

描述

BLPOP

BLPOP key [key ...] timeout

从第一个非空列表中弹出最左端的元素,或者在 timeout 秒内阻塞并等待可弹出的元素出现,返回被弹出的列表名及元素, timeout 为 0 表示无限等待

BRPOP

BRPOP key [key ...] timeout

从第一个非空列表中弹出最右端的元素,或者在 timeout 秒内阻塞并等待可弹出的元素出现,返回被弹出的列表名及元素, timeout 为 0 表示无限等待

RPOPLPUSH

RPOPLPUSH source destination

从 source 列表中弹出最右端的元素,然后将这个元素退出 destination 列表的最左端,并返回这个元素

BRPOPLPUSH

BRPOPLPUSH source destination timeout

从 source 列表中弹出最右端的元素,然后将这个元素退出 destination 列表的最左端,并返回这个元素;如果 source 列表为空,则在 timeout 秒内阻塞并等待可弹出元素出现

相关演示代码如下:

// 执行列表类型阻塞相关操作
func executeListBlockOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "source", "destination")))
	// 从第一个非空列表中弹出并返回列表最左端的值,最多等待 1秒,输出 -> ERROR:  redigo: nil returned
	handleResult(redis.Strings(conn.Do("BLPOP", "source", "destination", 1)))

	// 初始化
	handleResult(redis.Int(conn.Do("RPUSH", "source", "a", "b", "c")))
	handleResult(redis.Int(conn.Do("RPUSH", "destination", "d", "e", "f")))
	// 从第一个非空列表中弹出并返回列表最左端的值,无限等待,返回 -> a,source 变为 -> b c,destination 变为 -> d e f
	handleResult(redis.Strings(conn.Do("BLPOP", "source", "destination", 0)))
	// 从第一个非空列表中弹出并返回列表最右端的值,无限等待,返回 -> f,source 变为 -> b c,destination 变为 -> d e
	handleResult(redis.Strings(conn.Do("BRPOP", "destination", "source", 0)))

	// 从 source 弹出最右端元素,然后推入到 destination 最左端,并返回这个元素
	// 返回 -> c,source 变为 -> b,destination 变为 -> c d e
	handleResult(redis.String(conn.Do("RPOPLPUSH", "source", "destination")))
	// 从 source 弹出最右端元素,然后推入到 destination 最左端,并返回这个元素,无限等待
	// 返回 -> b,source 变为 -> <nil>,destination 变为 -> b c d e
	handleResult(redis.String(conn.Do("BRPOPLPUSH", "source", "destination", 0)))
	// 从 source 弹出最右端元素,然后推入到 destination 最左端,并返回这个元素,最多等待 1秒
	// 输出 -> ERROR:  redigo: nil returned,source 变为 -> <nil>,destination 变为 -> b c d e
	handleResult(redis.String(conn.Do("BRPOPLPUSH", "source", "destination", 1)))
}

对于阻塞弹出命令和弹出并推入命令,最常见的用例就是消息传递(messaging)和任务队列(task queue),将在以后对这两个主题进行介绍。 P44

练习题:通过列表来降低内存占用 P44

上篇文章中,我们使用了有序集合来记录用户最近浏览过的商品,并把用户浏览这些商品时的时间戳设置为分值,从而使得程序可以在清理旧会话的过程中或是在执行完购买操作后,进行相应的数据分析。但由于保存时间戳需要占用相应的空间,所以如果分析操作并不需要用到时间戳的话,那么就没有必要使用有序集合来保存用户最近浏览过的商品了。为此,请在保证语义不变的情况下,将 UpdateToken 函数里面是用的有序集合替换成列表。

提示:如果在解答这个问题时遇上困难的话,可以到 6.1.1 节中找找灵感。

  • 由于列表是有序的,所有最新访问的一定在列表的左端,所以每次操作时先删除列表中这个访问记录,再推入列表左端,最后修剪列表为长度为 25 即可。由于每次需要遍历整个列表,所以时间复杂度较高,但是列表长度总共只有 25 ,时间上相差不大,但是空间可以节省很多。
// 更新最近商品访问列表
func UpdateLatestViewedItem(conn redis.Conn, itemId int) {
	// 移除列表中所有值为 itemId 的元素
	_ = conn.Send("LREM", "latestViewedItem", 0, itemId)
	// 将最近访问的商品推入列表最左端
	_ = conn.Send("LPUSH", "latestViewedItem", itemId)
	// 修剪列表,保留最近访问的 25 个
	_ = conn.Send("LTRIM", "latestViewedItem", 0, 24)
	// 执行上述命令
	_ = conn.Flush()
}

集合 P44

一些常用的集合命令 P45

命令

格式

描述

SADD

SADD key member [member ...]

将一个或多个元素添加到集合中,返回添加到集合中的新元素的数量(不包括已存在的元素)

SREM

SREM keymember [member ...]

将一个或多个元素从集合中删除,返回成功从集合中删除的元素(不包括不存在的元素)

SISMEMBER

SISMEMBER key member

判断元素 member 是否在集合 key 中

SCARD

SCARD key

返回结合中元素的数量

SMEMBERS

SMEMBERS key

返回集合的所有元素

SRANDMEMBER

SRANDMEMBER key [count]

随机返回集合中一个或多个元素。count 为正数时,返回 count 个各不相同的元素(最多返回整个集合);count 为负数时,返回 |count| 个可能会重复的元素,无最长限制。

SPOP

SPOP key

随机移除并返回集合中的一个元素

SMOVE

SMOVE source destination member

将元素 member 从集合 source 移动到集合 destination 中

相关演示代码如下:

// 执行集合类型相关操作
func executeSetOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "source", "destination")))
	// 集合中添加三个元素,输出 -> 6,source 变为 -> 1 2 3 4 5 6 7
	handleResult(redis.Int(conn.Do("SADD", "source", 1, 2, 3, 4, 5, 6, 7, 1)))
	// 从集合中删除两个元素: 1 2,输出 -> 2,source 变为 -> 3 4 5 6 7
	handleResult(redis.Int(conn.Do("SREM", "source", 1, 2)))
	// 判断集合是否含有元素 3,输出 -> 1
	handleResult(redis.Int(conn.Do("SISMEMBER", "source", 3)))
	// 返回集合的元素个数,输出 -> 5
	handleResult(redis.Int(conn.Do("SCARD", "source")))
	// 返回集合的所有元素,输出 -> [3 4 5 6 7]
	handleResult(redis.Ints(conn.Do("SMEMBERS", "source")))
	// 随机返回集合中不同的 3 个元素,输出 -> [6 5 3] (随机结果可能存在不同,以实际为准)
	handleResult(redis.Ints(conn.Do("SRANDMEMBER", "source", 3)))
	// 随机返回集合中可重复的 6 个元素,输出 -> [7 5 6 3 7 6] (随机结果可能存在不同,以实际为准)
	handleResult(redis.Ints(conn.Do("SRANDMEMBER", "source", -6)))
	// 随机删除集合中的 1 个元素,输出 -> 3 ,source 变为 -> 4 5 6 7(随机结果可能存在不同,以实际为准)
	handleResult(redis.Int(conn.Do("SPOP", "source")))
	// 移动 source 集合中的元素 7 到 destination 集合中(由于前面存在随机,结果可能存在不同,以实际为准)
	// 输出 -> 1 ,source 变为 -> 4 5 6 ,destination 变为 -> 7
	handleResult(redis.Int(conn.Do("SMOVE", "source", "destination", 7)))
}
用于组合和处理多个集合的命令 P45

命令

格式

描述

SDIFF

SDIFF key [key ...]

返回存在于第一个集合,而不存在于其他集合的元素(差集)

SDIFFSTORE

SDIFFSTORE destination key [key ...]

将存在于第一个集合,而不存在于其他集合的元素(差集)存储到 destination 中,返回差集大小

SINTER

SINTER key [key ...]

返回同时存在于所有集合中的元素(交集)

SINTERSTORE

SINTERSTORE destination key [key ...]

将同时存在于所有集合中的元素(交集)存储到 destination 中,返回交集大小

SUNION

SUNIONkey [key ...]

返回至少存在于一个集合中的元素(并集)

SUNIONSTORE

SUNIONSTORE destination key [key ...]

将至少存在于一个集合中的元素(并集)存储到 destination 中,返回并集大小

相关演示代码如下:

// 执行集合类型多个集合相关操作
func executeSetMutiOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "source_1", "source_2", "source_3", "destination")))
	// 初始化
	handleResult(redis.Int(conn.Do("SADD", "source_1", 1, 2, 4, 8)))
	handleResult(redis.Int(conn.Do("SADD", "source_2", 2, 3, 4, 5)))
	handleResult(redis.Int(conn.Do("SADD", "source_3", 5, 6, 7, 8)))
	// 返回三个集合的差集,输出 -> [1]
	handleResult(redis.Ints(conn.Do("SDIFF", "source_1", "source_2", "source_3")))
	// 将三个集合的差集存储到 destination 中,输出 -> 1,destination 变为 -> 1
	handleResult(redis.Int(conn.Do("SDIFFSTORE", "destination", "source_1", "source_2", "source_3")))
	// 返回两个集合的交集,输出 -> [2 4]
	handleResult(redis.Ints(conn.Do("SINTER", "source_1", "source_2")))
	// 将两个集合的交集存储到 destination 中,输出 -> 2,destination 变为 -> 2 4
	handleResult(redis.Int(conn.Do("SINTERSTORE", "destination", "source_1", "source_2")))
	// 返回三个集合的并集,输出 -> [1 2 3 4 5 6 7 8]
	handleResult(redis.Ints(conn.Do("SUNION", "source_1", "source_2", "source_3")))
	// 将三个集合的并集存储到 destination 中,输出 -> 8,destination 变为 -> 1 2 3 4 5 6 7 8
	handleResult(redis.Int(conn.Do("SUNIONSTORE", "destination", "source_1", "source_2", "source_3")))
}

哈希表 P46

用于添加和删除键值对的散列操作 P47

命令

格式

描述

HMGET

HMGET key field [field ...]

从哈希表中获取一个或多个 field 的值

HMSET

HMSET key field value [field value ...]

向哈希表中设置一个或多个 field 的值

HDEL

HDEL key field [field ...]

从哈希表中删除一个或多个 field 的值

HLEN

HLEN key

返回哈希表中包含的 field 的数量

相关演示代码如下:

// 执行哈希表类型相关操作
func executeHashOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "hash")))
	// 向哈希表中设置一个或多个 field 的值,输出 -> OK,hash 变为 -> {field_1: value_1, field_2: value_2, field_3: value_3}
	handleResult(redis.String(conn.Do("HMSET", "hash", "field_1", "value_1", "field_2", "value_2", "field_3", "value_3")))
	// 从哈希表中获取一个或多个 field 的值,输出 -> [value_1 value_3 value_2]
	handleResult(redis.Strings(conn.Do("HMGET", "hash", "field_1", "field_3", "field_2")))
	// 从哈希表中删除一个或多个 field 的值,输出 -> 2,hash 变为 -> field_2: value_2}
	handleResult(redis.Int(conn.Do("HDEL", "hash", "field_1", "field_3")))
	// 返回哈希表中包含的 field 的数量,输出 -> 1
	handleResult(redis.Int(conn.Do("HLEN", "hash")))
}
哈希表的更高级特性 P47

命令

格式

描述

HEXISTS

HEXISTS key field

判断 field 是否存在于哈希表中

HKEYS

HKEYS key

返回哈希表中所有的 field

HVALS

HVALS key

返回哈希表中所有 field 的值

HGETALL

HGETALL key

返回哈希表中所有的 field 及其值

HINCRBY

HINCRBY key field increment

将哈希表中 field 的值增加整数 increment

HINCRBYFLOAT

HINCRBYFLOAT key field increment

将哈希表中 field 的值增加浮点数 increment

相关演示代码如下:

// 执行哈希表类型高级特性相关操作
func executeHashFeatureOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "hash")))
	// 初始化
	handleResult(redis.String(conn.Do("HMSET", "hash", "field_1", "value_1", "field_2", "value_2", "field_3", "3")))
	// 判断 field 是否存在于哈希表中,输出 -> 1
	handleResult(redis.Int(conn.Do("HEXISTS", "hash", "field_1")))
	// 返回哈希表中所有的 field,输出 -> [field_1 field_2 3]
	handleResult(redis.Strings(conn.Do("HKEYS", "hash")))
	// 返回哈希表中所有 field 的值,输出 -> [value_1 value_2 value_3]
	handleResult(redis.Strings(conn.Do("HVALS", "hash")))
	// 返回哈希表中所有的 field 及其值,输出 -> map[field_1:value_1 field_2:value_2 field_3:3]
	handleResult(redis.StringMap(conn.Do("HGETALL", "hash")))
	// 将哈希表中 field 的值增加 1,输出 -> 4,field_3 的值变为 -> 4
	handleResult(redis.Int(conn.Do("HINCRBY", "hash", "field_3", 1)))
	// 将哈希表中 field 的值增加 -1.5,输出 -> 2.5,field_3 的值变为 -> 2.5
	handleResult(redis.Float64(conn.Do("HINCRBYFLOAT", "hash", "field_3", -1.5)))
}

如果哈希表包含的值非常大,可以先使用 HKEYS 取出所有的 field,然后再使用 HGET 取出值,防止一次取出多个大体积的值而导致服务器阻塞。 P48

有序集合 P48

一些常用的有序集合命令 P49

命令

格式

描述

ZADD

ZADD key socre member [score member ...]

向有序集合中添加一个或多个元素及其分值

ZREM

ZREM key member [member ...]

从有序集合中删除一个或多个元素及其分值

ZCARD

ZCARD key

返回有序集合中元素的个数

ZINCRBY

ZINCRBY key increment member

给有序集合中的元素的分值增加 increment

ZCOUNT

ZCOUNT key min max

返回分值在 [min, max] 范围内的元素的数量

ZRANK

ZRANK key member

返回元素的升序排名(升序,从 0 开始)

ZREVRANK

ZREVRANK key member

返回元素的降序排名(降序,从 0 开始)

ZSCORE

ZSCORE key member

返回元素的排名的分值

ZRANGE

ZRANGE key start stop [WITHSCORES]

返回升序排名在 [start, stop] 范围内的元素,WITHSCORES 选项会同时在相应的元素后返回分值

ZRANRANGE

ZRANGE key start stop [WITHSCORES]

返回降序排名在 [start, stop] 范围内的元素,WITHSCORES 选项会同时在相应的元素后返回分值

相关演示代码如下:

// 执行有序集合相关操作
func executeZsetOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "zset")))
	// 有序集合中添加 5 个元素及其分值,输出 -> 5,zset 变为 -> ["a":1, "b":2, "c":3, "d":4, "e":5]
	handleResult(redis.Int(conn.Do("ZADD", "zset", 1, "a", 2, "b", 3, "c", 4, "d", 5, "e")))
	// 有序集合中删除 3 个元素及其分值,输出 -> 2,zset 变为 -> ["a":1, "b":2, "c":3]
	handleResult(redis.Int(conn.Do("ZREM", "zset", "d", "e", "f")))
	// 返回有序集合的元素个数,输出 -> 3
	handleResult(redis.Int(conn.Do("ZCARD", "zset")))
	// 给有序集合中的元素的分值增加 0.5,输出 -> 1.5,a 的值变为 -> 1.5
	handleResult(redis.Int(conn.Do("ZINCRBY", "zset", 1, "a")))
	// 给有序集合中的元素的分值增加 -1.5,输出 -> 0.5,a 的值变为 -> 0.5
	handleResult(redis.Float64(conn.Do("ZINCRBY", "zset", -1.5, "a")))
	// 返回分值在 [1, 3] 范围内的元素的数量,输出 -> 2
	handleResult(redis.Int(conn.Do("ZCOUNT", "zset", 1, 3)))
	// 返回元素的升序排名(升序,从 0 开始),输出 -> 0
	handleResult(redis.Int(conn.Do("ZRANK", "zset", "a")))
	// 返回元素的降序排名(降序,从 0 开始),输出 -> 2
	handleResult(redis.Int(conn.Do("ZREVRANK", "zset", "a")))
	// 返回元素的排名的分值,输出 -> 0.5
	handleResult(redis.Float64(conn.Do("ZSCORE", "zset", "a")))
	// 返回升序排名在 [1, 2] 范围内的元素,并且返回分值,输出 -> map[b:2 c:3]
	handleResult(redis.StringMap(conn.Do("ZRANGE", "zset", "1", "2", "WITHSCORES")))
	// 返回降序排名在 [1, 2] 范围内的元素,并且返回分值,输出 -> map[a:0.5 b:2]
	handleResult(redis.StringMap(conn.Do("ZREVRANGE", "zset", "1", "2", "WITHSCORES")))
}
有序集合的范围性命令及并交集命令 P50

命令

格式

描述

ZRANGEBYSCORE

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

返回升序分值在 [min, max] 范围内的元素,WITHSCORES 选项会同时在相应的元素后返回分值

ZREVRANGEBYSCORE

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

返回降序分值在 [max, min] 范围内的元素,WITHSCORES 选项会同时在相应的元素后返回分值

ZREMRANGEBYRANK

ZREMRANGEBYRANK key start stop

移除升序排名在 [start, stop] 范围内的元素

ZREMRANGEBYSCORE

ZREMRANGEBYSCORE key min max

移除升序分值在 [min, max] 范围内的元素

ZINTERSTORE

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]]  [AGGREGATE SUM|MIN|MAX]

求一个或多个(有序)集合的交集,并存储到 destination 中,WEIGHTS 权重存在时,weight 数量必须等于 numkeys(集合默认分值为 1)

ZUNIONSTORE

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]]  [AGGREGATE SUM|MIN|MAX]

求一个或多个(有序)集合的并集,并存储到 destination 中,WEIGHTS 权重存在时,weight 数量必须等于 numkeys(集合默认分值为 1)

相关演示代码如下:

// 执行有序集合范围及交并集相关操作
func executeZsetMutiOperation(conn redis.Conn) {
	// 删除原有值
	handleResult(redis.Int(conn.Do("DEL", "zset_1", "zset_2", "destination")))
	// 初始化
	handleResult(redis.Int(conn.Do("ZADD", "zset_1", 1, "a", 2, "b", 3, "c")))
	handleResult(redis.Int(conn.Do("ZADD", "zset_2", 2, "b", 3, "c", 4, "d")))
	// 返回升序分值在 [1, 2] 范围内的元素,并且返回分值,输出 -> map[a:1 b:2]
	handleResult(redis.StringMap(conn.Do("ZRANGEBYSCORE", "zset_1", "1", "2", "WITHSCORES")))
	// 返回降序分值在 [4, 3] 范围内的元素,并且返回分值,输出 -> map[c:3 d:4]
	handleResult(redis.StringMap(conn.Do("ZREVRANGEBYSCORE", "zset_2", "4", "3", "WITHSCORES")))
	// 移除升序排名在 [1, 1] 范围内的元素,输出 -> 1,zset_1 变为 -> ["b":2, "c":3]
	handleResult(redis.Int(conn.Do("ZREMRANGEBYRANK", "zset_1", "1", "1")))
	// 移除降序排名在 [2, 2] 范围内的元素,输出 -> 1,zset_2 变为 -> ["c":3, "d":4]
	handleResult(redis.Int(conn.Do("ZREMRANGEBYSCORE", "zset_2", "2", "2")))
	// 求 2 个有序集合的交集,权重分别为 2, 3,分值默认采用加法
	// 并存储到 destination 中,输出 -> 1,destination 变为 ->
	handleResult(redis.Int(conn.Do("ZINTERSTORE", "destination", 2, "zset_1", "zset_2", "WEIGHTS", 2, 3)))
	// 求 2 个有序集合的并集,权重分别为 2, 3,分值指定采用最大值
	// 并存储到 destination 中,输出 -> 3,destination 变为 -> ["a":2, "c":9, "d":12]
	handleResult(redis.Int(conn.Do("ZUNIONSTORE", "destination", 2, "zset_1", "zset_2", "WEIGHTS", 2, 3, "AGGREGATE", "MAX")))
}

所思所想

  • 这一章又是比较枯燥的命令介绍,不过还是坚持看下来了,发现还是挺有用的,有很多平常没接触的命令,也没想到 Redis 竟然这么强大。
  • 即使时比较精细地阅读,也不需要全部阅读,可以快速浏览已经知道的基础,重点还是要放在不知道的地方,带着思考去阅读,先想然后用实践验证。