Redis 入门 01 - 五种数据类型

1. 安装 Redis


docker pull redis:3.0-alpine
docker images
docker run --restart=always -d -p 6379:6379 -v /root/redis/data:/home/renzheng/redis/data xxx --requirepass "password"
docker exec -it xxx sh

2. 热身

2.1 使用 redis-cli,并验证密码:

renzheng@qingdao:~$ docker exec -it 813 sh
/data # redis-cli
127.0.0.1:6379> auth bP623f@dhNfb
OK

选择数据库 (Redis 命令不区分大小写)

127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK

2.2 获得符合规则的 keys 列表

  • *:任意个字符
  • ?:一个或多个字符
  • a[a-c]:aa、ab、ac

keys * 会遍历 Redis 中所有键,如果键的数量较多则会影响性能,生产环境不建议使用

127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr fool
(integer) 1
127.0.0.1:6379[1]> keys fo* 
1) "foo"
2) "fool"

设值和取值:

127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> get bar
"1"

2.3 判断一个键是否存在

存在返回整数类型 1,否则返回 0

127.0.0.1:6379[1]> exists bar
(integer) 1

2.4 删除键

127.0.0.1:6379[1]> del bar
(integer) 1

Redis 中的 del 命令不支持批量删除,但是我们可以凭借 Linux 的管道删除多个键:

redis-cli keys "user*" | xargs redis-cli del

2.5 获得键值的数据类型

type 命令用于获取键值的数据类型,返回值可能是 string(字符串)、hash(散列)、list(列表)、set(集合类型)、zset(有序集合类型)。

127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> type bar
string
127.0.0.1:6379[1]> get bar
"1"

3. 字符串类型

字符串类型是 Redis 中最基本的数据类型,能够存储任何形式的字符串,包括二进制数据。例如,可以存储一个邮箱,JSON 序列化之后的对象,甚至是一张图片。一个字符串类型键允许存储的是数据最大容量是 512 MB。

3.1 命令

3.1.1 赋值和取值

SET key value
GET key

例如:

127.0.0.1:6379[1]> set greet "Hi!"
OK
127.0.0.1:6379[1]> get greet
"Hi!"

如果键不存在会返回空结果

127.0.0.1:6379[1]> get a
(nil)

3.1.2 递增数字

INCR num

当存储的字符串是整数形式时,Redis 提供了一个 INCR 命令,可以让当前的键值递增,并返回递增后的值,如果键不存在会默认赋值 0。例如:

127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr foo
(integer) 2
127.0.0.1:6379[1]> type foo
string
127.0.0.1:6379[1]> get foo
"2"

如果键不是整数,则出现如下错误:

127.0.0.1:6379[1]> incr greet
(error) ERR value is not an integer or out of range

包括 INCR 在内的所有 Redis 命令均为原子操作,不会出现并发冲突问题。

3.2 实践

3.2.1 文章访问量统计

每次访问文章使用 INCR 命令使响应的键值递增。

键一般使用 object:id:property 的形式,例如:post:1:page.view

3.2.2 生成自增 id

每新增一个对象都使用 INCR 命令。

INCR user:count

3.2.3 存储文章数据

对象序列化(JSON,MessagePack 等方式)。以存储 id 为 1的 文章为例:

set post:1:data str

3.3 其他命令

3.3.1 增加指定的整数

INCRBY 命令可以通过 increment 参数指定一次增加的数值

INCRBY key increment
127.0.0.1:6379[1]> set foo 100
OK
127.0.0.1:6379[1]> incrby foo 100
(integer) 200
127.0.0.1:6379[1]> get foo
"200"

3.3.2 减少指定的整数

DECR 命令与 INCR 命令用法相同,区别是让数值减少。与 INCRBY 命令的相似的便是 DECRBY 命令。

3.3.3 增加指定的浮点数

INCRBYFLOAT 命令类似 INCR 命令,差别是可以增加一个双精度浮点数。

INCRBYFLOAT key increment

例如:

127.0.0.1:6379[1]> set foo 1.000001
OK
127.0.0.1:6379[1]> incrbyfloat foo 0.000000003
"1.000001003"

3.3.4 向尾部追加值

APPEND 命令用来向键值末尾追加值。如果键不存在将该键的值设置为 value

APPEND key value

例如:

127.0.0.1:6379[1]> set foo "Hello"
OK
127.0.0.1:6379[1]> append foo ", world!"
(integer) 13
127.0.0.1:6379[1]> get foo
"Hello, world!"

3.3.5 获取字符串长度

STRLEN key

例如:

127.0.0.1:6379[1]> strlen foo
(integer) 13

3.3.6 同时获得/设置多个键值

MSET/MGET 命令与 GET/SET 命令相似,只不过 MSET/MGET 可以设置/获取多个键值。

MGET key [key ...]
MSET key value [key value ...]

例如:

127.0.0.1:6379[1]> mset foo 1 bar 2
OK
127.0.0.1:6379[1]> mget foo bar
1) "1"
2) "2"

3.3.7 位操作

GETBIT key offset (offset 从 0 开始)
SETBIT key offset value
BITCOUNT key
BITOP operation destkey key [key ...]

将 foo 设置为 "abc"(01100001 01100010 ..

127.0.0.1:6379[1]> set foo abc
OK

获取第 1、6 个 bit

127.0.0.1:6379[1]> getbit foo 1
(integer) 1
127.0.0.1:6379[1]> getbit foo 6
(integer) 0

如果偏移量超出键值实际长度,则默认为 0

127.0.0.1:6379[1]> getbit foo 30
(integer) 0

BITCOUNT 命令可以获得字符串类型键中值为 1 的二进制位个数,例如:

127.0.0.1:6379[1]> bitcount foo
(integer) 10

可以通过参数限制统计的字节范围,例如只统计前两个字节:

127.0.0.1:6379[1]> bitcount foo 0 1
(integer) 6

SETBIT 命令可以设置字符串类型键指定位置的二进制位的值,返回值是该位置的旧值:

127.0.0.1:6379[1]> setbit foo 1 0
(integer) 1
127.0.0.1:6379[1]> get foo
"!bc"

如果设置一个不存在的键的指定二进制位的值,会自动将其前面的位赋值为 0:

127.0.0.1:6379[1]> setbit test 10 0
(integer) 0
127.0.0.1:6379[1]> get test
"\x00\x00"

如果指定的二进制位超过了键值的实际长度,那么会自动将中间的位全部设置为 0

127.0.0.1:6379[1]> setbit foo 31 0
(integer) 0
127.0.0.1:6379[1]> get foo
"!bc\x00"

BITOP 命令可以对多个字符串类型键进行位运算,并将结果存在 destkey 指定的键中。支持的运算操作有 ANDORXORNOT

127.0.0.1:6379[1]> set foo bar
OK
127.0.0.1:6379[1]> set foo aaa
OK
127.0.0.1:6379[1]> set bar bbb
OK
127.0.0.1:6379[1]> bitop or res foo bar
(integer) 3
127.0.0.1:6379[1]> get res
"ccc"

4. 散列(hash)类型

散列类型(hash)的键值也是一种字典结构,其存出了字段和字段值的映射,但是字段值只能是字符串,不支持其他数据类型。一个散列类型键至多包含 2^32 -1 个字段。

散列类型适合存储对象,以 object:id 构成键名,使用字段表示对象的属性,自字段值则存储属性值,例如:

[图片上传失败...(image-cf3390-1653622114110)]

散列类型不像关系型数据库那样要求所有的记录都有同样的属性,而存在无法为单独的某条记录增加属性的问题。Redis 完全可以自由地为任何键增减字段而不影响其他键。

4.1 常用命令

4.1.1 取值与赋值

HSET key field value
HGET key field
HMSET key field value [field value ...]]
HMGET key field [field ...]
HGETALL key

例如:

127.0.0.1:6379[1]> hset car color red (不存在该字段则建立该字段,返回 1;存在则更新,返回 0)
(integer) 1
127.0.0.1:6379[1]> hset car name "BMW"
(integer) 1
127.0.0.1:6379[1]> hset car price "500000"
(integer) 1
127.0.0.1:6379[1]> hmget car color name price
1) "red"
2) "BMW"
3) "500000"
127.0.0.1:6379[1]> hgetall car
1) "color"
2) "red"
3) "name"
4) "BMW"
5) "price"
6) "500000"
127.0.0.1:6379[1]> type car
hash

4.1.2 判断字段是否存在

HEXISTS key field

例如:

127.0.0.1:6379[1]> hexists car color
(integer) 1 (存在返回 1,不存在返回 0)

4.1.3 当字段不存在时赋值

HSETNX key field value

HSETINX 命令与 HSET 命令相似,只不过 HSETNX 只有字段不存在时才赋值,字段如果存在则不执行任何操作。

127.0.0.1:6379[1]> hsetnx person age 1
(integer) 0 // 存在返回 0
127.0.0.1:6379[1]> hget person age
"20"
127.0.0.1:6379[1]> hsetnx person height 165
(integer) 1 // 字段不存在,设值,且返回 1

4.1.4 增加数字

HINCRBY key field increment

HINCRBY 命令与 INCRBY 命令相似,如果字段不存在。Hash 类型没有类似 INCR 的命令,不过可以通过执行 HINCRBY key field 1 来实现。如果键或者字段不存在,那么将自动创建键和字段,并赋值为 increment

例:

127.0.0.1:6379[1]> hincrby car price 1
(integer) 500001
127.0.0.1:6379[1]> hincrby person age 20
(integer) 20
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"

4.1.5 删除字段

hdel key field

例:

127.0.0.1:6379[1]> hset person name "Renzheng"
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"
3) "name"
4) "Renzheng"
127.0.0.1:6379[1]> hdel person name
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"

4.2 实践

4.2.1 存储文章数据

[图片上传失败...(image-43c2a3-1653622114110)]

4.2.2 存储文章缩略名

使用一个的 slug.to.id hash 类型键用于存储文章缩略名和文章 ID 的对应关系。

如果需要发布文章,伪代码如下:

// 获取文章 ID
$postId = INCR posts:count
// 判断文章缩略名 slug 是否可用,如果不可用则赋值
$isSlugAvailable = HSETNX slug.to.id $slug $postId

// 缩略名存在
if $isSlugAvailable = 0
    exit

HMSET post:$postId title $title content $content slug $slug

4.3 其他命令

4.3.1 只获取字段名或字段值

127.0.0.1:6379[1]> hkeys car
1) "color"
2) "name"
3) "price"
127.0.0.1:6379[1]> hvals car
1) "red"
2) "BMW"
3) "500001"

4.3.2 获得字段数量

127.0.0.1:6379[1]> hlen car
(integer) 3

5. 列表(list)类型

List 类型可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。list 类型内部由双向链表实现,所以向列表两端添加元素的时间复杂度为 O(1),获取越接近两端的元素越快,代价是通过索引访问元素比较慢。

场景:新鲜事(插入最新,获取最新)、日志。

借助 list 类型,Redis 还可以作为队列使用。

一个 list 类型键最多容纳 2^32 - 1 个元素。

5.1 常用命令

5.1.1 向列表两端添加元素

LPUSH key value [value ...]
RPUSH key value [value ...]

LPUSH 命令用来向列表左边添加元素,返回值为添加元素后列表的长度。

例如:

127.0.0.1:6379[1]> lpush nums 1
(integer) 1
127.0.0.1:6379[1]> lpush nums 2 3
(integer) 3

按照以上命令,nums 中元素变化如下:

[]
[1]
[3, 2, 1]

5.1.2 从列表两端弹出元素

LPOP key
RPOP key

LPOP 命令可以从列表左边弹出一个元素。该命令执行两个操作:

  1. 将列表左边的元素从列表中移除
  2. 返回被移除的元素

例如:

127.0.0.1:6379[1]> lpop nums
"3"

5.1.3 获取列表中元素的个数

LLEN key

如果 key 不存在,LLEN 命令返回 0。例如:

127.0.0.1:6379[1]> llen nums
(integer) 2
127.0.0.1:6379[1]> llen foo // foo 不存在
(integer) 0

LLEN 命令的功能类似于关系型数据库中的 select count(*) from table_name,但是 LLEN 的时间复杂度为 O(1),使用时会直接读取现成的值,并不需要遍历一遍获得数据。

5.1.4 获得列表片段

LRANGE key start stop

LRANGE 可以获得列表中的一个片段,返回索引从 startstop 之间的元素(索引从 0 开始,包括 stop 元素)。

例如:

127.0.0.1:6379[1]> lrange nums 0 1
1) "2"
2) "1"

LRANGE 命令也支持负索引,表示从右边开始计算,如 -1 表示从最右边第一个元素开始,-2 表示最右边第二个元素,依此类推。

127.0.0.1:6379[1]> lrange nums -2 -1
1) "2"
2) "1"

如果 stop 大于实际的索引范围,则会返回到列表中最右边的元素。

5.1.5 删除列表中指定的值

LREM key count value

LREM 命令将删除前 count 个值为 value 的元素,返回实际删除的元素。

例如:

127.0.0.1:6379[1]> lpush nums 1 0 1 0 1 0 1 0 1 0
(integer) 10
127.0.0.1:6379[1]> lrange nums 0 -1 
 1) "0"
 2) "1"
 3) "0"
 4) "1"
 5) "0"
 6) "1"
 7) "0"
 8) "1"
 9) "0"
10) "1"
127.0.0.1:6379[1]> lrem nums 3 1
(integer) 3
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "0"
3) "0"
4) "0"
5) "1"
6) "0"
7) "1"

根据 count 值的不同,LREM 命令的执行方式会略有差异:

  • count > 0 时,LREM 命令会从左边删除前 count 个值为 value 的元素;

  • count < 0 时,LREM 命令会删除从右边开始删除前 |count| 个值为 value 的元素;

  • count = 0 时,LREM 命令将删除所有值为 value 的元素。

5.2 实践

5.2.1 存储文章 ID 列表

使用键 posts:list 记录文章 ID 列表。当发布新文章时,使用 LPUSH 命令把文章的 ID 加入至这个列表中,删除文章时将列表中的文章 ID 删除。可以使用 LRANGE 命令实现文章分页列表,伪代码如下:

$postPerPage = 10
$start = ($currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1
$postIds = LRANGE posts:list $start $end

# 循环获取文章信息
for $id in $postIds
    print HGET post:$id title

5.2.2 存储文章评论

将文章评论序列化之后,使用字符串的形式将评论存入形如 posts:id:comments 的列表中。

伪代码如下:

$serializedComment = serialize($author, $email, $time, $content)
LPUSH post:1:comments $serializedComment

读取时,依然使用 LRANGE 命令。

5.3 其他命令

5.3.1 获得/设置指定索引的元素值

LINDEX key index
LSET KEY index value

LINDEX 用来返回指定索引的元素,索引从 0 开始。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "0"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> lindex nums 0
"0"
127.0.0.1:6379[1]> lindex nums 2
"8"

LSET 命令将索引为 index 的元素设置为 value,例如:

127.0.0.1:6379[1]> lset nums 0 99999
OK
127.0.0.1:6379[1]> lrange nums 0 -1
 1) "99999"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"

5.3.2 只保留列表指定片段

LTRIM key start end

LTRIM 命令可以删除指定索引范围之外的所有元素,其指定的列表范围的方法和 LRANGE 命令相同。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "99999"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> ltrim nums 1 -1
OK
127.0.0.1:6379[1]> lrange nums 0 -1
1) "9"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"

5.3.3 向列表中插入元素

LINSERT key BEFORE|AFTER pivot value

LINSERT 命令在列表中从左到右查找值为 pivot 的元素,然后根据第二个参数是 BEFORE 还是 AFTER 决定将 value 插入到该元素的前面还是后面。LINSERT 命令的返回值为插入后列表元素的个数。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "1"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> linsert nums before 1 0
(integer) 11
127.0.0.1:6379[1]> lrange nums 0 -1
 1) "0"
 2) "1"
 3) "9"
 4) "8"
 5) "7"
 6) "6"
 7) "5"
 8) "4"
 9) "3"
10) "2"
11) "1"

5.3.4 将元素从一个列表转移至另一个列表

RPOPLPUSH src des

RPOPLPUSH 命令会先从 src 列表的右边弹出一个元素,然后将其加入至 des 列表的左边,并返回这个元素的值。整个过程是原子的。

6. 集合(set)类型

在集合中每个元素都是不同的,而且没有顺序。一个 set 类型的键可以至多存储 2^32 - 1 个字符串。

[图片上传失败...(image-e0c4ba-1653622114110)]

集合类型在 Redis 内部是使用值为空的 Hash Table 实现的。

6.1 常用命令

6.1.1 增加/删除元素

SADD key member [member ...]
SREM key [member] [member ...]

SADD 命令用于向集合中添加一个元素或多个元素,如果键不存在则自动创建,元素已存在则忽略。返回值为成功加入元素的数量。

例如:

127.0.0.1:6379[1]> sadd foo a
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 2

SREM 命令用于从集合中删除一个或者多个元素,返回成功删除的个数。

例如:

127.0.0.1:6379[1]> srem foo a d
(integer) 1

6.1.2 获得集合中所有元素

SMEMBERS key

SMEMBERS 命令从集合中返回所有元素。例如:

127.0.0.1:6379[1]> del foo
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 3
127.0.0.1:6379[1]> smembers foo
1) "c"
2) "b"
3) "a"

6.1.3 判断元素是否存在于集合中

SISMEMBER key member

时间复杂度为 O(1),SISMEMBER 当值存在时返回 1,当值不存在或者键不存在时返回 0。例如:

127.0.0.1:6379[1]> sismember foo a
(integer) 1
127.0.0.1:6379[1]> sismember foo d
(integer) 0

6.1.4 集合运算

SDIFF key [key ...]
SINTER key [key ...]
SUNION key [key ...]
  • SDIFF 用来对集合之间执行差集运算。

    127.0.0.1:6379[1]> sadd aset a b c
    (integer) 3
    127.0.0.1:6379[1]> sadd bset b c d
    (integer) 3
    127.0.0.1:6379[1]> sdiff aset bset
    1) "a"
    127.0.0.1:6379[1]> smembers aset
    1) "c"
    2) "b"
    3) "a"
    
  • SINTER 用来对多个集合执行交集运算。

    127.0.0.1:6379[1]> sinter aset bset
    1) "c"
    2) "b"
    
  • SUNION 用来对多个集合执行并集运算。

    127.0.0.1:6379[1]> sunion aset bset
    1) "c"
    2) "b"
    3) "d"
    4) "a"
    

6.2 实践

6.2.1 存储文章标签

一篇文章的各个标签均是不同的,而且展示时对这些标签的顺序没有要求,可以使用 set 类型键存储文章标签。对每篇文章使用形如 posts:id:tags 的键存储该篇文章的标签。

伪代码如下:

SADD post:1:tags Java Spring MyBatis
SREM post:1:tags MyBatis

// 显示所有标签
$tags = SMEMBERS post:1:tags

6.2.2 通过标签查询文章

使用形如 tag:标签:posts 的 set 类型键存储每个标签对应标签。

6.3 其他命令

6.3.1 获取集合中元素的个数

SCARD key

SCARD 命令用于获取集合中元素的个数,例如:

127.0.0.1:6379[1]> scard aset
(integer) 3

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

SDIFFSTORE des key [key ...]
SINTERSTORE des key [key ...]
SUNIONSTORE des key [key ...]

不直接返回运算结果,而将结果存储在 des 键中。

127.0.0.1:6379[1]> sdiffstore cset aset bset
(integer) 1
127.0.0.1:6379[1]> smembers cset
1) "a"

6.3.3 随机获取集合中的元素

SRANDMEMBER key [count]

SRANDMEMBER 命令用于随机从集合中获取一个元素,例如:

127.0.0.1:6379[1]> srandmember aset
"b"

也可以传递一个 count 参数一次获得多个元素,而根据 count 参数的正负不同返回结果略有差异:

  • count 为正数时,SRANDMEMBER 命令将从集合中随机获得 count 个不重复的元素;
  • count 为负数时,SRANDMEMBER 命令将从集合中随机获得可能相同的 |count| 个元素。

6.3.4 从集合中弹出一个元素

SPOP key

由于集合是无序的,因此 SPOP 命令会从集合中随机选择一个元素弹出。例如:

127.0.0.1:6379[1]> spop aset
"a"
127.0.0.1:6379[1]> smembers aset
1) "c"
2) "b"

7. 有序集合

有序集合(sorted set) 类型在 set 类型的基础上为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除、判断是否存在等 set 类型支持的操作,还能进行获得分数最高(最低)的前 N 个元素、获得指定分数范围内的元素等与分数相关的操作。

虽然集合中每个元素都不相同,但是分数可以相同。

7.1 命令

7.1.1 增加元素

ZADD key score member [score member]

ZADD 命令用于向 sorted set 中添加一个或多个元素及他们的分数,如果该元素已经存在,那么则会用新的分数替代旧的分数。ZADD 命令的返回值为新加入集合中的元素个数。例如:

127.0.0.1:6379[1]> zadd scoreboard 98 Tom 87 Mike 94 Mary
(integer) 3
127.0.0.1:6379[1]> zadd scoreboard 86.5 Mike
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard +inf Mike // 设置分数为正无穷
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard -inf Mike // 设置分数为负无穷
(integer) 0

7.1.2 获得元素的分数

ZSCORE key member

例如:

127.0.0.1:6379[1]> zscore scoreboard Mike
"86.5"

7.1.3 获得在某个排名范围内的元素列表

ZRANGE key start stop [withscores]
ZREVRANGE key start stop [withscores]

ZRANGE 命令会按照元素的分数从小到大排序返回索引从 startstop 之间的所有元素(包括两端),索引方式与 LRANGE 命令相同。ZREVRANGE 命令按照分数从大到小排序。

127.0.0.1:6379[1]> zrange scoreboard 0 2
1) "Mike"
2) "Mary"
3) "Tom"
127.0.0.1:6379[1]> zrange scoreboard 0 2 withscores
1) "Mike"
2) "86.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"
127.0.0.1:6379[1]> zrevrange scoreboard 0 2 withscores
1) "Tom"
2) "98"
3) "Mary"
4) "94"
5) "Mike"
6) "86.5"

如果两个元素的分数相同,则按照字典顺序排序。

7.1.4 获取指定分数范围内的元素

ZRANGEBYSCORE key min max [withscore] [limit offset count]

ZRANGEBYSCORE 命令按照元素分数从小到大的顺序返回分数在 minmax 之间的元素,例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard 80 90
1) "Mike"

如果希望分数不包括端点值,则可以在分数前加上 (,例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard 80 86.5
(empty list or set)

minmax 还支持无穷大,类似于 ZADD 命令,-inf+inf 分别表示负无穷和正无穷。例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard (80 +inf withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"

limit offset count 表示在获得列表的基础上,向后偏移 offset 个元素,并只获取前 count 个元素。例如:

// 获取高于 60 分并从第 2 个人开始的 3 个人
127.0.0.1:6379[1]> zrangebyscore scoreboard (60 +inf withscores limit 1 3
1) "Mary"
2) "94"
3) "Tom"
4) "98"

ZREVRANGEBYSCORE 命令命令不仅按照元素分数从大到小排序,而且该命令的 minmax 参数顺序和 ZRANGEBYSCORE 命令是相反的。

7.1.5 增加某个元素的分数

ZINCRBY key increment member

ZINCRBY 命令可以增加某个元素的分数,返回值为更改之后的分数。例如:

127.0.0.1:6379[1]> zincrby scoreboard 2 Mike
"88.5"
127.0.0.1:6379[1]> zrange scoreboard 0 -1 withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"

7.2 实践

7.2.1 实现文章按照访问量排序

使用键名 posts:page.view 的键记录每篇文章的 ID 和访问量,每次访客访问一篇文章,则通过 ZINCRBY posts:page.view 1 postId 更新访问量。伪代码如下:

$postsPerpage = 10
$start = $(currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1;
$postIds = ZREVRANGE posts:page.view $start $end

foreach $id in $postIds
    $title = HGET post:$id title

7.2.2 改进按照时间排序

同样采用有序集合,记录文章 ID 和 Unix 时间

7.3 其他命令

7.3.1 获得集合中元素的数量

ZCARD key

例如:

127.0.0.1:6379[1]> zcard scoreboard
(integer) 3

7.3.2 获得指定分数范围内元素个数

ZCOUNT key min max

例如:

127.0.0.1:6379[1]> zcount scoreboard 80 90
(integer) 1

7.3.3 删除一个或多个元素

ZREM key member

ZREM 返回值是成功删除元素的数量

127.0.0.1:6379[1]> zrem scoreboard Mike
(integer) 1
127.0.0.1:6379[1]> zrange scoreboard 0 -1
(empty list or set)

7.3.4 按照排名范围删除元素

ZREMRANGEBYRANK key start stop

ZREMRANGEBYRANK 命令按照元素从小(最小为 0)到大排序删除排名在指定范围内的所有元素,并返回删除元素的数量。例如:

127.0.0.1:6379[1]> zremrangebyrank scoreboard 1 3
(integer) 2
127.0.0.1:6379[1]> zrange scoreboard 0 -1
1) "Mike"

7.3.5 按照分数范围删除元素

ZREMRANGEBYSCORE key min max

ZREMRANGEBYSOCRE 会删除指定分数范围内所有的元素,参数 minmax 的特性和 ZRANGEBYSCORE 命令中的一样。返回值是删除元素的数量。

7.3.6 获得元素的排名

ZRANK key member
ZREVRANK key member

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

7.3.6 计算有序集合的交集

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

ZINTERSTORE 命令用来计算多个有序集合的交集,并将结果存储在 des 键中(同样以有序集合类型存储),返回值为 des 键中的元素个数。

des 键中元素的分数由 AGGREGATE 参数决定:

  • AGGREGATE 参数是 SUM (默认)时,des 键中的元素分数是每个参与计算集合中该元素分数的和;
  • AGGREGATE 参数是 MIN (默认)时,des 键中的元素分数是每个参与计算集合中该元素分数的最小值;
  • AGGREGATE 参数是 MAX (默认)时,des` 键中的元素分数是每个参与计算集合中该元素分数的最大值;

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

另外还有一个命令 ZUNIONSTORE 计算集合并集,用法与 ZINTERSTORE 命令相同。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容