当前位置 : 主页 > 网络编程 > lua >

lua – 如何使用Redis将搜索文本与其他条件相结合?

来源:互联网 收集:自由互联 发布时间:2021-06-23
我使用Redis成功地编写了文本搜索和其他标准的交集.要实现这一点,我正在使用Lua脚本.问题是我不仅要阅读,还要从该脚本中编写值.从Redis 3.2可以通过调用redis.replicate_commands()来实现这一
我使用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之外进行部分处理(比如迭代光标或交叉匹配),但它会影响应用程序的整体性能.
>我不想自己部署Redis实例来使用3.2版.
>上面的标准(价格范围和名称)只是一个简单的例子.我有其他领域和比赛类型,不仅仅是那些.
>我不确定我存储数据的方式是否是最佳方式.我愿意听取有关它的建议.

问题不是你要写入数据库,而是你在HSCAN之后进行写操作,这是一个非确定性的命令.

在我看来,很少有理由在Lua脚本中使用SCAN命令.该命令的主要目的是允许您以小批量执行操作,这样您就不会锁定处理巨大密钥空间(或散列密钥空间)的服务器.由于脚本是原子的,因此使用HSCAN无济于事 – 您仍然会锁定服务器,直到整个过程完成.

以下是我可以看到的选项:

如果您不能冒险使用冗长的命令锁定服务器:

>在客户端上使用HSCAN.这是最安全的选择,但也是最慢的.

如果您想在单个原子Lua命令中进行尽可能多的处理:

>使用Redis 3.2和脚本效果复制.>在脚本中进行扫描,但将值返回给客户端并从那里开始写入. (也就是Karthikeyan Gopall的回答.)>而不是HSCAN,在脚本中执行HKEYS并使用Lua的模式匹配过滤结果.由于HKEYS是确定性的,因此后续写入不会有问题.当然,缺点是您必须首先读入所有键,无论它们是否与您的模式匹配. (虽然HSCAN也是散列大小的O(N).)

网友评论