doc: 阅读sorted set文档

This commit is contained in:
asahi
2025-09-08 14:51:17 +08:00
parent 1c9b73cd5d
commit a7206d120e

View File

@@ -71,6 +71,17 @@
- [Field Expiration](#field-expiration) - [Field Expiration](#field-expiration)
- [Common field expiration use cases](#common-field-expiration-use-cases) - [Common field expiration use cases](#common-field-expiration-use-cases)
- [Field Expiration examples](#field-expiration-examples) - [Field Expiration examples](#field-expiration-examples)
- [Sorted sets](#sorted-sets)
- [ZRANGEBYSCORE](#zrangebyscore)
- [ZREMRANGEBYSCORE / ZREM](#zremrangebyscore--zrem)
- [Inclusive and exclusive](#inclusive-and-exclusive)
- [ZRANK / ZREVRANK](#zrank--zrevrank)
- [`Lexicographical scores`](#lexicographical-scores)
- [ZRANGEBYLEX](#zrangebylex)
- [Updating the score: leaderboards](#updating-the-score-leaderboards)
- [Leaderboard Example](#leaderboard-example)
- [ZADD](#zadd)
- [ZINCRBY](#zincrby)
# redis # redis
@@ -1073,3 +1084,180 @@ print(expire_time)
# prints [1717668041] # your actual value may vary # prints [1717668041] # your actual value may vary
``` ```
### Sorted sets
redis sorted set是一个包含unique strings的集合其中unique strings会关联一个score并且strings会按照score进行排序。`如果多个string存在相同的score那么拥有相同score的strings将会按照字典序进行排序`。
sorted sets的用例场景包括如下
- `Leaderboards`: 可以通过sorted sets维护一个ordered list其可被用于实现排行榜
- `RateLimiter`: 通过sorted list可以构建一个`sliding-window rate limiter`从而避免过多的api调用
- 在实现`sliding-window rate limiter`时可以将时间戳作为score因为可以快速获取一个时间范围内的调用数量
可以将sorted sets看作是set和hash的混合
- 和set一样sorted sets由unique strings组成
- 和hash一样sorted sets中元素由一个关联的floating point value被称为score
sorted set的使用示例如下
```redis-cli
> ZADD racer_scores 10 "Norem"
(integer) 1
> ZADD racer_scores 12 "Castilla"
(integer) 1
> ZADD racer_scores 8 "Sam-Bodden" 10 "Royce" 6 "Ford" 14 "Prickett"
(integer) 4
```
`ZADD`和`SADD`类似,但是其接收一个用于表示`score`的额外参数。和`SADD`类似,可以使用`ZADD`来添加多个`score-value pairs`。
> #### Implementation
> sorted sets实现的数据结构中同时使用了`skip list`和`hash table`两种数据结构故而每次向zset中添加元素时其操作的复杂度为o(log(n))`
>
> 并且,在获取元素时,由于元素已经被排序,获取操作无需其他的额外开销。
`ZRANGE`的顺序为从小到大,`ZREVRANGE`的顺序则是从大到小
```redis-cli
> ZRANGE racer_scores 0 -1
1) "Ford"
2) "Sam-Bodden"
3) "Norem"
4) "Royce"
5) "Castilla"
6) "Prickett"
> ZREVRANGE racer_scores 0 -1
1) "Prickett"
2) "Castilla"
3) "Royce"
4) "Norem"
5) "Sam-Bodden"
6) "Ford"
```
在上述示例中0和-1代表index位于`[0, len-1]`范围内的元素。(负数代表的含义和`LRANGE`命令中相同)
在`ZRANGE`命令中指定`withscores`也能够在返回zset中value时同时返回score
```redis-cli
> ZRANGE racer_scores 0 -1 withscores
1) "Ford"
2) "6"
3) "Sam-Bodden"
4) "8"
5) "Norem"
6) "10"
7) "Royce"
8) "10"
9) "Castilla"
10) "12"
11) "Prickett"
12) "14"
```
#### ZRANGEBYSCORE
除了上述操作外sorted sets还支持对`operate on ranges`。可以通过`ZRANGEBYSCORE`来实现`get all racers with 10 or fewer points`的操作:
```redis-cli
> ZRANGEBYSCORE racer_scores -inf 10
1) "Ford"
2) "Sam-Bodden"
3) "Norem"
4) "Royce"
```
上述示例中,`ZRANGEBYSCORE racer_score -inf 10`向redis请求`返回score位于negative infinity和10之间both included的元素`。
#### ZREMRANGEBYSCORE / ZREM
如果想要丛zset中移除元素可以调用`ZREM`命令。同样的sorted sets也支持`remove ranges of elements`的操作,可通过`ZREMRANGEBYSCORE`命令来实现。
```redis-cli
> ZREM racer_scores "Castilla"
(integer) 1
> ZREMRANGEBYSCORE racer_scores -inf 9
(integer) 2
> ZRANGE racer_scores 0 -1
1) "Norem"
2) "Royce"
3) "Prickett"
```
上述示例中,通过`ZREMRANGEBYSCORE racer_scores -inf 9`命令实现了`remove all the racers with strictly fewer than 10 points`的操作。
`ZREMRANGEBYSCORE`会返回其移除的元素个数。
##### Inclusive and exclusive
在使用`ZRANGEBYSCORE`指定`min`和`max`时,可以分别将其指定为`-inf`和`+inf`。故而在获取zset中比`xx`大或比`xx`小的所有元素时,可以使用`-inf`和`+inf`此时无需知道当前zset中的最大/最小元素。
默认情况下,`interval specified by min and max is closed`(inclusive)。但是,可以将其指定为`open interval`(exclusive)只需要在score前添加`(`符号即可,示例如下:
```redis-cli
ZRANGEBYSCORE zset (1 5
```
上述示例中,会返回位于`(1, 5]`区间内的元素。
而`ZRANGEBYSCORE zset (5 (10`命令则是会返回`(5, 10)`区间内的元素。
#### ZRANK / ZREVRANK
sorted sets还支持`get-rank operation`,通过`ZRANK`可以返回`position of an element in the set of ordered elements`。
`ZREVRANK`命令的作用和`ZRANK`类似,但是`ZREVRANK`返回的值为`从大到小的降序ranking`。
使用示例如下所示:
```redis-cli
> ZRANK racer_scores "Norem"
(integer) 0
> ZREVRANK racer_scores "Norem"
(integer) 2
```
#### `Lexicographical scores`
自redis 2.8其,引入了`getting ranges lexicograhpically`的新特性其假设sorted set中的所有元素都拥有相同的score。
与`lexicographical ranges`进行交互的主要命令如下:
- ZRANGEBYLEX
- ZREVRANGEBYLEX
- ZREMRANGEBYLEX
- ZLEXCOUNT
使用示例如下所示:
```redis-cli
> ZADD racer_scores 0 "Norem" 0 "Sam-Bodden" 0 "Royce" 0 "Castilla" 0 "Prickett" 0 "Ford"
(integer) 3
> ZRANGE racer_scores 0 -1
1) "Castilla"
2) "Ford"
3) "Norem"
4) "Prickett"
5) "Royce"
6) "Sam-Bodden"
> ZRANGEBYLEX racer_scores [A [L
1) "Castilla"
2) "Ford"
```
在上述示例中,可以通过`ZRANGEBYLEX`按照字典序对range进行请求。
##### ZRANGEBYLEX
ZRANGEBYLEX的语法如下
```
ZRANGEBYLEX key min max [limit offset count]
```
和`ZRANGEBYSCORE`命令不同的是,`ZRANGEBYSCORE`在指定范围时,默认是`included`的;而`ZRANGEBYLEX`必须通过`[`和`(`来显式指定inclusive或exclusive。
而在指定min和max时`-`和`+`分别则代表negatively infinite和positive infinite。故而`ZRANGEBYLEX myzset - +`命令代表返回zset中所有的元素。
#### Updating the score: leaderboards
支持对sorted set中元素的score进行更新。在更新sorted set中元素的score时只需要`再次调用ZADD命令即可`sorted set会更新score更新操作的时间复杂度为`O(log(N))`。
#### Leaderboard Example
在通过zset实现leaderboard时由如下两种方式对user score进行更新
- 在得知user当前score的情况下可以直接通过`ZADD`命令来进行覆盖
- 如果想要针对当前的score进行`增加`操作时,可以使用`ZINCRBY`命令
```redis-cli
> ZADD racer_scores 100 "Wood"
(integer) 1
> ZADD racer_scores 100 "Henshaw"
(integer) 1
> ZADD racer_scores 150 "Henshaw"
(integer) 0
> ZINCRBY racer_scores 50 "Wood"
"150"
> ZINCRBY racer_scores 50 "Henshaw"
"200"
```
##### ZADD
当当前添加的元素已经在sorted set中存在时`ZADD`命令会返回`0`,否则`ZADD`命令会返回`1`。
##### ZINCRBY
而`ZINCRBY`命令则是会返回更新后的new score。