Redis get成员,其得分介于最小值和最大值之间

Redis get成员,其得分介于最小值和最大值之间,redis,Redis,我有一个sql表,有3列:BIGINT StartNumber、BIGINT EndNumber、BIGINT LocationId,我需要能够这样做 Select LocationId where StartNumber < @number and EndNumber > @number. 当我有@number=7时,我应该得到LocationId=1 我如何在redis中做到这一点 我本想将此表移动到redis,使用排序集和ZRANGEBYSCORE,但它对我不起作用: 1)

我有一个sql表,有3列:
BIGINT StartNumber、BIGINT EndNumber、BIGINT LocationId
,我需要能够这样做

Select LocationId where StartNumber < @number and EndNumber > @number.
当我有@number=7时,我应该得到LocationId=1

我如何在redis中做到这一点

我本想将此表移动到redis,使用排序集和
ZRANGEBYSCORE
,但它对我不起作用: 1) 当我使用ZADD key score member[score][member]时,即使使用nx参数,我也无法添加具有相同成员和不同分数的2个元素:
zadd myset nx 1“17”2“17”
-它将添加一个元素,然后更新其分数,而不是添加两个元素。 2) 当我添加以下内容时:
zadd set1 2“a”4“b”6“c”10“d”
然后尝试执行zrangebyscore set1 3(希望获得分数包括3的成员),我得到的结果为空


另外,所有命令都在redis网站的示例页面上执行。

换句话说,您的问题是“如何将N个数字范围映射到一个位置”。一种方法是使用两个排序集,一个用于
StartNumber
,另一个用于
EndNumber
。由于成员必须是唯一的,因此我们还需要通过将开始/结束值作为成员的一部分来确保。例如,使用示例数据,可以这样做:

ZADD StartNumber 1 "1:5:1" 6 "6:9:1" 10 "10:16:2"
ZADD EndNumber 5 "1:5:1" 9 "6:9:1" 16 "10:16:2"
要查找@number=7的位置,请执行
ZRANGEBYSCORE StartNumber-inf 7
ZRANGEBYSCORE EndNumber 7+inf
并将结果相交。剩下的就是在冒号(
)上拆分intesect的结果,并使用第三个元素作为位置


注意:如果你的应用程序确保没有重叠范围,并且每个“数字”只能有一个位置,那么你只需一组就可以得到相同的结果。

据我所知,你没有重叠,每个间隔只映射到一个位置(?),间隔也没有间隙。基于此,您只能使用一个具有下限(或上限)值的排序列表:

ZADD StartNumber 1 "1:5:1" 6 "6:9:1" 10 "10:16:2"
然后您可以使用:

ZREVRANGEBYSCORE StartNumber 7 -inf LIMIT 0 1
这将是O(log(N))。

(这是我第一次对同一个问题给出两个答案——也许我会得到一个徽章或sumthin';)

双排序集方法是一种推广,因此,其目的是解决比OP需要的问题更大的问题集(如对第一个答案的评论所述)。这种方法也是无效的,因为查询是O(logn)+O(N),所以当N较大(例如5M)时,这可能不是一个好主意

但是,为了满足要求,并且考虑到范围不重叠,实际上可以只使用单个排序集和更简单的查询。集合的成员应该通过连接
EndNumber
LocationId
来添加,并且它们的分数应该设置为各自的
StartNumber
,因此为了示例:

ZADD ranges 1 "5:1" 6 "9:1" 10 "16:2"
给定@number,使用以下Redis Lua代码(O(logn))获取相关的
LocationId


添加两个或更多具有不同分数的成员的目的是什么?@MatíasFidemrAzer在sql中我有一系列与位置id相关的数字,比如1到5之间的数字与locationid=1相关,而排序集只能为每个元素(分数成员)添加2列。我想,我需要为sql表中的每一行添加元素,比如星端定位和尾端定位。或者我应该创建两个排序集,如建议的Bellow谢谢你的回答。我是否正确理解如果我有500万个记录和<代码> @号码<代码>在中间某个地方(或者这甚至无关紧要)
ZRANGEBYSCORE StartNumber-inf@number
ZRANGEBYSCORE EndNumber@number+inf
将返回所有500万条记录,我需要在网站服务器端将它们相交,而不使用任何其他Redis命令?您可以使用Lua脚本在Redis端完成所有操作,但客户端(即网站服务器)除外这也是一种有效的方法。但是,如果你真的有5百万个这样的值,你可能想考虑一个不同的方法,不管相交发生在哪里…您需要管理多少个值、位置和数字范围?此表中约有500万条记录,每条记录有3个bigint列-StartNumber、EndNumber和LocationId。LocationID是重复的,因为某些位置可以分配多个编号范围。Hmm。所以我假设范围不重叠(即,每个给定的bigint最多有一个位置)。除了此查询之外,还有哪些操作?数据更新是否频繁和/或是否存在其他类型的读取?我可能有一个或两个想法哦,关于这些开始和结束数字-你真的在用完整的bigint空间(假设-2^63..2^63)来表示这些范围吗?我同意-这也是我开始意识到的:)
ZADD ranges 1 "5:1" 6 "9:1" 10 "16:2"
-- rangelookup.lua
-- http://stackoverflow.com/questions/32185898/redis-get-member-where-score-is-between-min-and-max/32186675
-- A **non inclusive** range search on a Sorted Set with the following data:
--   score = <StartNumber>
--   member = <EndNumber>:<LocationId>
--
-- KEYS[1] - Sorted Set key name
-- ARGV[1] - the number to search
--
-- reply - the relevant id, nil if range doesn't exist
-- 
-- usage example: redis-cli --eval rangelookup.lua ranges , 7

local number = tonumber(ARGV[1])
local data = redis.call('ZREVRANGEBYSCORE', KEYS[1], number, '-inf', 'WITHSCORES', 'LIMIT', 0, 1)
local reply = nil

if data ~= nil and number > tonumber(data[2]) then
  local to, id = data[1]:match( '(.*):(.*)' )
  if tonumber(to) > number then
    reply = id
  end
end

return reply
$ redis-cli --eval rangelookup.lua ranges , 7
"1"
$ redis-cli --eval rangelookup.lua ranges , 9
(nil)
$ redis-cli --eval rangelookup.lua ranges , 99
(nil)