在Redis中为Ruby重新创建zdiffstore。

我试图创建一个类似于 Redis sdiffstore 的事务,用于有序集合。 我有一个 Redis “main”(temp:'..u_id)有序集合和第二个“remove”集合。我想返回“main”排序集,在删除任何匹配的“remove”集合成员之后的得分。

我的结构有大约200个“main”键,每个键中有~ 200个得分成员。 "remove" 集合对于每一个主键都有大约50个成员。对于每一个请求,我需要循环遍历所有~ 200个用户,这证明是一个代价高昂的过程。以下是我现有的服务器端脚本的一部分:

#Generate list of user ids
local usercard = redis.call('smembers', 'temp:user')

--#Loop through all available users
--#Get array of users
for i=1,table.getn(usercard)-1,1 do
    local u_id = usercard[i]

    --#Create a copy of the user and store into temp:user_id
    redis.call('zunionstore', 'temp:..u_id,1,'user:'..u_id)

    --#remove unwanted
    redis.call('zrem','temp:'..u_id, unpack(redis.call('smembers','remove:'..u_id)))
end

zunionstore 和 zrem 的组合是一个非常昂贵的命令,而循环证明是限制因素,防止能力扩展。我知道我没有充分利用 Redis 线程,因为无法在一切错综复杂之前扩展到 ~50个并发连接。

作为一个相对较新的Redis用户:

1)Redis是否是挑战的最佳db选择?

2)是否有更有效的关键结构?

3)是否有更有效的方法来构建服务器端脚本,或者是否最好执行一对调用(zrange用于“main”排序集,smembers用于“remove”集)来在Ruby中进行处理,鉴于Big(O)将仍然很大?

点赞
用户204011
用户204011

我不确定我完全理解你的问题。你真的需要写入数据还是只需要在应用程序端获取过滤后的列表?你是否总是需要为所有200个用户做这样的操作,还是只需要为一个用户?

此外,你在循环中不应该减一,你可能会错过最后一个用户。

如果你需要所有用户,并且不需要将结果保留在 Redis 中,你可以考虑像这样的代码(未经测试):

local r = {}
local t, l, s, w
for _,u_id in ipairs(redis.call('smembers', 'temp:user')) do
  t = redis.call('zrange', 'user:' .. u_id, 0, -1, "withscores")
  l = redis.call('smembers', 'remove:' .. u_id)
  s = {}
  for _,x in ipairs(l) do s[x] = true end
  w = {}
  for i=1,#t,2 do
    if not s[t[i]] then w[t[i]] = w[t[i+1]] end
  end
  r[u_id] = w
end

return r
2013-11-18 13:07:35