lua – 如何使用Redis将搜索文本与其他条件相结合?
我使用Redis成功地编写了文本搜索和其他标准的交集.要实现这一点,我正在使用Lua脚本.问题是我不仅要阅读,还要从该脚本中编写值.从Redis 3.2可以通过调用redis.replicate_commands()来实现这一点,但不能在3.2之前实现.
以下是我存储值的方法. 名称 > HSET product:name 'Cool product' 1 > HSET product:name 'Nice product' 2 价钱 > ZADD product:price 49.90 1 > ZADD product:price 54.90 2 然后,为了获得所有匹配’ice’的产品,我打电话给: > HSCAN product:name 0 MATCH *ice* 但是,由于HSCAN使用游标,我必须多次调用它来获取所有结果.这是我使用Lua脚本的地方: local cursor = 0 local fields = {} local ids = {} local key = 'product:name' local value = '*' .. ARGV[1] .. '*' repeat local result = redis.call('HSCAN',key,cursor,'MATCH',value) cursor = tonumber(result[1]) fields = result[2] for i,id in ipairs(fields) do if i % 2 == 0 then ids[#ids + 1] = id end end until cursor == 0 return ids 因为不可能将脚本的结果与另一个调用一起使用,比如SADD键EVAL(SHA)….而且,在脚本中也不可能使用全局变量.我已经更改了字段循环中的部分以访问脚本外部的ID列表: if i % 2 == 0 then ids[#ids + 1] = id redis.call('SADD',KEYS[1],id) end 我不得不将redis.replicate_commands()添加到第一行.通过这个更改,我可以从调用脚本时传递的密钥中获取所有ID(参见KEYS [1]). 最后,为了获得列表100产品ID的价格在40到50之间,其中名称包含“ice”,我执行以下操作: > ZUNIONSTORE tmp:price 1 product:price WEIGHTS 1 > ZREMRANGEBYSCORE tmp:price 0 40 > ZREMRANGEBYSCORE tmp:price 50 +INF > EVALSHA b81c2b... 1 tmp:name ice > ZINTERSTORE tmp:result tmp:price tmp:name > ZCOUNT tmp:result -INF +INF > ZRANGE tmp:result 0 100 我使用ZCOUNT调用预先知道我将拥有多少个结果页面,数量为/ 100. 正如我之前所说,这与Redis 3.2很好地配合.但是当我试图在AWS上运行代码时,它只支持Redis高达2.8,我无法再让它工作了.我不知道如何在不使用脚本或不从脚本编写的情况下使用HSCAN游标进行迭代.有一种方法可以在Redis 2.8上运行吗? 一些考虑: >我知道我可以在Redis之外进行部分处理(比如迭代光标或交叉匹配),但它会影响应用程序的整体性能. 解决方法
问题不是你要写入数据库,而是你在HSCAN之后进行写操作,这是一个非确定性的命令.
在我看来,很少有理由在Lua脚本中使用SCAN命令.该命令的主要目的是允许您以小批量执行操作,这样您就不会锁定处理巨大密钥空间(或散列密钥空间)的服务器.由于脚本是原子的,因此使用HSCAN无济于事 – 您仍然会锁定服务器,直到整个过程完成. 以下是我可以看到的选项: 如果您不能冒险使用冗长的命令锁定服务器: >在客户端上使用HSCAN.这是最安全的选择,但也是最慢的. 如果您想在单个原子Lua命令中进行尽可能多的处理: >使用Redis 3.2和脚本效果复制.>在脚本中进行扫描,但将值返回给客户端并从那里开始写入. (也就是Karthikeyan Gopall的回答.)>而不是HSCAN,在脚本中执行HKEYS并使用Lua的模式匹配过滤结果.由于HKEYS是确定性的,因此后续写入不会有问题.当然,缺点是您必须首先读入所有键,无论它们是否与您的模式匹配. (虽然HSCAN也是散列大小的O(N).) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |