字符串 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 数据结构简介.md):

// 执行字符串类型数字相关操作
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 竟然这么强大。

  • 即使时比较精细地阅读,也不需要全部阅读,可以快速浏览已经知道的基础,重点还是要放在不知道的地方,带着思考去阅读,先想然后用实践验证。

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/redis-in-action

Redis 实战 —— 04. Redis 数据结构常用命令简介的更多相关文章

  1. Redis启动服务和String常用命令

    Redis启动服务和String常用命令 1. 启动Redis服务 E:\redis>redis-server.exe redis.windows.conf _._ _.-``__ ''-._ ...

  2. Redis实战之Redis + Jedis

    用Memcached,对于缓存对象大小有要求,单个对象不得大于1MB,且不支持复杂的数据类型,譬如SET 等.基于这些限制,有必要考虑Redis! 相关链接: Redis实战 Redis实战之Redi ...

  3. Redis实战之Redis + Jedis[转]

    http://blog.csdn.net/it_man/article/details/9730605 2013-08-03 11:01 1786人阅读 评论(0) 收藏 举报   目录(?)[-] ...

  4. 第18章 Redis数据结构常用命令

    18-1 字符串的一些基本命令 18-1 :配置Spring关于Redis字符串的运行环境 <bean id="poolConfig" class="redis.c ...

  5. Redis各数据结构常用命令

    redis 通用API keys * 遍历所有key 一般不在生产环境中使用 redis单线程,容易阻塞其他命令执行 O(n) dbsize 计算key的总数 O(1)exists 检查key是否存在 ...

  6. Redis 实战 —— 05. Redis 其他命令简介

    发布与订阅 P52 Redis 实现了发布与订阅(publish/subscribe)模式,又称 pub/sub 模式(与设计模式中的观察者模式类似).订阅者负责订阅频道,发送者负责向频道发送二进制字 ...

  7. Redis入门,Jedis和常用命令

    一.Redis简介 1.关于关系型数据库和nosql数据库 关系型数据库是基于关系表的数据库,最终会将数据持久化到磁盘上,而nosql数据     库是基于特殊的结构,并将数据存储到内存的数据库.从性 ...

  8. redis五种数据类型和常用命令及适用场景

    一.redis的5种数据类型: 1.基础理解: string 字符串(可以为整形.浮点型和字符串,统称为元素) list 列表(实现队列,元素不唯一,先入先出原则) set 集合(各不相同的元素) h ...

  9. Redis实战之Redis命令

    阅读目录 1. 字符串命令 2. 列表命令 3. 集合命令 4. 散列命令 5. 有序集合命令 6. 发布与订阅命令 7. 小试牛刀 Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结 ...

随机推荐

  1. Scala中的IO操作及ArrayBuffer线程安全问题

    通过Scala对文件进行读写操作在实际业务中应用也比较多,这里介绍几种常用的方式,直接上代码: 1. 从文件中读取内容 object Main { def loadData(): Array[Stri ...

  2. js下 Day20、综合案例

    一.购物车 效果图: 功能思路分析: 1. 面向对象框架 2. 模拟数据 1.多个店铺数组套对象 2.每个店铺多个商品,数组套对象

  3. C语言中++*x和*++x的区别

    ++跟*的优先级一样,如果两个同时出现,运算是从右往左(不是常规的从左往右),所以: ++*x即++(*x),先取x的值,然后让值自加1:(地址没变,指针指向的值变了.搞不懂的话自己用快递做例子) * ...

  4. 多任务-python实现-gevent(2.1.15)

    @ 目录 1.说明 2.代码 关于作者 1.说明 上个博文携程实现的多任务 依然是一个进程,一个线程,只不过执行了不同的代码部分 这里使用gevent,或者greenlet 当gevent执行的时候遇 ...

  5. 报错 ncclCommInitRank failed.

    环境 4 GeForce GTX 1080 GPUS docker image nnabla/nnabla-ext-cuda-multi-gpu:py36-cuda102-mpi3.1.6-v1.14 ...

  6. Solon 特性简集,相较于 Springboot 有什么区别?

    Solon 是一个类似Springboot的微型开发框架,也是一个不基于Servlet的开发框架.项目从2018年启动以来,参考过大量前人作品:历时两年,3500多次的commit:内核保持0.1m的 ...

  7. Docker - 配置加速器

    https://www.daocloud.io/mirror#accelerator-doc curl -sSL https://get.daocloud.io/daotools/set_mirror ...

  8. ajax上传单个文件

    jsp页面 <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML> ...

  9. 身份证前6位地址码+码表+MySQL

    insert into smd_address_code(add_code,address) values('110000','北京市'); insert into smd_address_code( ...

  10. 设计模式——从HttpServletRequestWrapper了解装饰者模式

    从一个业务开始 最近项目上紧急需要,为了应付一个不知道啥的安全检测,我们要给系统追加防XSS注入的功能,这里有经验的JavaWeb开发就会想到,用过滤器或者基于项目框架的拦截器来做,但是顺着这个思路下 ...