首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在莴苣(4.x) for Redis中,如何减少往返次数,并将一个命令的输出用作另一个命令的输入,特别是对于Georadius

在莴苣(4.x) for Redis中,如何减少往返次数,并将一个命令的输出用作另一个命令的输入,特别是对于Georadius
EN

Stack Overflow用户
提问于 2015-12-12 13:26:10
回答 2查看 1.2K关注 0票数 0

我看到了这个pass results to another command in redis,并且使用了via命令行,这个命令很好用:

代码语言:javascript
复制
src/redis-cli keys '*' | xargs src/redis-cli mget

然而,我们如何才能通过生菜达到同样的效果(我开始尝试4.0.2最后)

另外,在以下情况下,解决这一问题特别重要:

假设我们使用的是地理定位功能,并使用GEOADD添加了一组“我的位置-类别”的位置。

代码语言:javascript
复制
GEOADD "category-1" 8.6638775 49.5282537 "location-id:1" 8.3796281 48.9978127 "location-id:2" 8.665351 49.553302 "location-id:3"

接下来,假设我们做了一个GeoRadius,在8.6582361 -1类的10公里半径范围内得到8.6582361 49.5285495的位置。

现在,当我们得到“位置-id:1”和“位置-id:3”时

考虑到我已经为上面的键设置了值“location:1”和“location:3”

我想管道命令来做GEORADIUS以及做mget对所有匹配的结果。

Redis提供了这样的功能吗?

和/或如何通过莴苣客户端库实现这一点,而无需首先手动迭代GEORADIUS的结果,然后执行手动mget。

对于使用它的程序来说,这将是更有效的性能。

有人知道我们该怎么做吗?

更新--这是我前面讨论的场景的管道命令:

代码语言:javascript
复制
src/redis-cli GEORADIUS "category-1" 8.6582361 49.5285495 10 km | xargs src/redis-cli mget

现在我们需要知道如何通过生菜来做这件事。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-16 23:47:52

在深入研究Lua脚本之后,我的结论是,按照Itamar的建议,只有通过Lua脚本才能以这种方式消除往返。

最后,我创建了一个lua脚本文件(myscript.lua),如下所示

代码语言:javascript
复制
local locationKeys = redis.call('GEORADIUS', 'category-1', '8.6582361', '49.5285495', '10', 'km' ) 
if unpack(locationKeys) == nil then
    return nil
else
    return redis.call('MGET', unpack(locationKeys))
end

**我们当然应该发送参数.这只是一个poc :)

现在您可以通过命令执行它了。

代码语言:javascript
复制
src/redis-cli EVAL "$(cat myscript.lua)" 0

然后,为了减少将整个脚本发送到Redis执行的网络开销,我们可以选择向Redis注册脚本。

Redis将为该脚本的未来引用提供一个sha1摘要代码,可用于对该脚本的下一次调用。

这可以按以下方式进行:

代码语言:javascript
复制
src/redis-cli SCRIPT LOAD "$(cat myscript.lua)"

这应该返回一个sha1代码,如下所示:49730a2ed3034ee48f818e486tpbdf1b500b19e

接下来的调用可以使用下面的代码完成

代码语言:javascript
复制
src/redis-cli evalsha 49730aa2ed3034ee48f818e486b2bdf1b500b19e 0

然而,令人悲哀的是,只有在redis实例运行时,sha1摘要才会被记住。如果重新启动,sha1摘要将丢失。然后再次执行脚本加载。如果脚本中没有任何变化,那么sha1 1摘要代码将是相同的。

理想情况下,当通过客户端api使用时,我们应该首先尝试evalsha,如果这返回了一个“没有匹配的脚本”错误,然后作为回退做脚本加载,并再次获取sha1代码,并创建一个内部映射,并使用该sha1代码进行进一步的调用。

这完全可以通过生菜来完成。我能找到解决这些的方法。希望这能为这个问题的解决方案提供一个很好的见解。

票数 1
EN

Stack Overflow用户

发布于 2015-12-12 14:27:59

:永远不要使用KEYS,如果必须的话,始终使用SCAN

这其实不是一个关于生菜或Java的问题,所以我可以回答它:)

您要做的是使用读取操作(GEORADIUS)的结果作为另一个读取操作(MGET)的输入(键名)。这种类型的流不能被流水线化,就因为这样--流水线意味着您不需要马上为操作找到答案,但在您的情况下,您需要这样做。

然而。

由于您正在使用MGET读取字符串键,所以最好将所有内容(请记住,我们是NoSQL)去denormalize,并将这些键的内容存储在排序集的成员中,例如:

代码语言:javascript
复制
GEOADD "category-1" 8.6638775 49.5282537 "location-id:1:moredata:evenmoredata:{maybe a JSON document here}:orperhapsmsgpack"

这将允许您通过一个GEORADIUS调用获取位置及其“数据”。当然,对location:1数据的任何更新都需要跨所有类别进行。

关于Lua脚本的注意:在本例中,虽然Lua脚本肯定可以来回保存,但是任何这样的脚本都将违背最佳实践/不集群安全。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34240338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档