Redis ZRANGEBYSCORE 命令返回有序集合的指定 key 中,所有 score 值介于 min 和 max 之间(包含等于 min 和 max)的成员(默认情况下),也可以通过给 min 和 max 对应参数前增加 (
符号来使用可选的开区间(小于或大于)。
有序集合成员按 score 值递增(从小到大)顺序排列;此外,具有相同 score 值的成员按字典序(lexicographical order)来排列(该属性是有序集提供的,不需要额外的计算)。
命令格式
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
可用版本:>=1.0.5
时间复杂度:O(log(N)+M),N 为有序集合的基数(成员个数),M 为指定的返回条数。如果 M 为常数(例如,始终要求使用 LIMIT 获取前 10 个元素),则可以将其视为 O(log(N))。
命令参数
参数名 | 可选 | 参数解释 |
---|---|---|
min | 必需 | 最小的 score(分数)值。 |
max | 必需 | 最大的 score(分数)值。 |
WITHSCORES | 可选 | 该参数将有序集成员及其 score 值一起返回。该选项自 Redis 2.0 版本起可用。 |
LIMIT offset count | 可选 | 取值的范围,offset、表示结果的起始位置(或偏移位置),count、表示返回结果的数量。值得注意的是,当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N)。 |
补充:
- min 和 max 可以是 -inf 和 +inf,这样一来,你就可以在不知道有序集的最低和最高 score 值的情况下,使用 ZRANGEBYSCORE 这类命令。
- 默认情况下,区间的取值使用闭区间(包含阈值),也可以通过给定参数前增加
(
符号来使用可选的开区间。
举个例子:
ZRANGEBYSCORE zset (1 88
返回所有符合条件 1 < score <= 88
的成员,而
ZRANGEBYSCORE zset (88 (100
则返回所有符合条件 88 < score < 100
的成员。
命令返回值
返回指定区间内,带有 score 值(可选项)的有序集成员的列表。
使用场景
排行榜
各类(用户或物品)排行榜可采用 Redis 的有序集合结构,其中成员对应用户 id 或物品 id,分数对应其分数。
用户实时行为
在搜索推荐系统中,经常会把用户最近的一些行为作为重要的特征,我们可以借助于 Redis 的有序集合数据结构保存用户相关的行为(如搜索、点击、关注等等),key 为行为标识与用户标识组合而成,如 search_click_188 表示用户 188 的搜索点击数据相关 key,成员对应相应行为的 item_id(或 user_id),分数(score)一般存储对应行为发生的时间戳,一般情况下精确到秒即可。
带有权重的元素的随机选择
有一个常见的场景,就是从集合中随机选择一个元素,但是不同的元素具有不同的权重,对应权重影响对应元素的被选择概率。
对此,我们可以借助 Redis 的 ZRANGEBYSCORE 命令解决该问题。
假设您有元素 A,B 和 C 的权重为 1、2 和 3。您计算权重之和,即 1 + 2 + 3 = 6,此时,您可以使用以下算法将所有元素添加到排序集中:
SUM = ELEMENTS.TOTAL_WEIGHT // 6 in this case.
SCORE = 0
FOREACH ELE in ELEMENTS
SCORE += ELE.weight / SUM
ZADD KEY SCORE ELE
END
这意味着我们做了如下操作:
A to score 0.16
B to score 0.5
C to score 1
此时,如果每次想要获得加权随机元素时,只需计算介于 0 和 1 之间的随机数即可,因此操作如下:
RANDOM_ELE = ZRANGEBYSCORE key RAND() +inf LIMIT 0 1
注:其中 RAND() 为命令写入时,生成的随机数,并非 Redis 自带的命令(或函数)。
示例
redis> ZADD beer 1 ale
(integer) 1
redis> ZADD beer 2 lager
(integer) 1
redis> ZADD beer 3 wild
(integer) 1
redis> ZRANGEBYSCORE beer 1 2 # 分数在闭区间 1 到 2 的成员
1) "ale"
2) "lager"
redis> ZRANGEBYSCORE beer (1 2 # 分数在半开半闭区间 1 到 2 的成员
1) "lager"
redis> ZRANGEBYSCORE beer (1 (2 # 分数在开区间 1 到 2 的成员
(empty list or set)
redis> ZRANGEBYSCORE beer -inf +inf # 返回所有的成员
1) "ale"
2) "lager"
3) "wild"
redis> ZRANGEBYSCORE beer 1 (3 WITHSCORES # 分数在半闭半开区间 1 到 3 的成员及分数
1) "ale"
2) "1"
3) "lager"
4) "2"
redis> ZRANGEBYSCORE beer 1 3 LIMIT 1 2 # 分数在闭区间 1 到 3 的成员,并以 1 为偏移量,返回 2 个成员
1) "lager"
2) "wild"