我成功地使用Redis編寫了文本搜索和其他條件的交集。爲了達到這個目的,我使用了一個Lua腳本。問題是我不僅在閱讀,而且還在寫這個腳本的價值。從Redis 3.2開始,可以通過調用redis.replicate_commands()
來實現,但不能在3.2之前完成。如何使用Redis將搜索文本與其他標準結合起來?
以下是我如何存儲值。
名稱
價格
> 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 key 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,在名稱中包含「冰」之間,我做了以下內容:
> 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
調用預先知道我會有很多結果頁,做count/100
。
正如我之前所說的,這與Redis 3.2很好地協作。但是當我試圖在AWS上運行代碼時,它只支持Redis高達2.8,我無法再使它工作了。我不知道如何使用HSCAN
遊標進行迭代,而無需使用腳本或者不使用腳本進行寫入。有一種方法可以使它在Redis 2.8上運行?
一些注意事項:
- 我知道我可以Redis的外面做加工的部分(比如迭代光標或交叉匹配),但它會影響到應用的整體性能。
- 我不想自己部署Redis實例來使用3.2版本。
- 上面的標準(價格範圍和名稱)只是一個簡單的例子。我有其他領域和類型的比賽,不僅僅是那些。
- 我不確定我存儲數據的方式是否是最好的方法。我願意聽取關於它的建議。
@KevinChristopherHenry以下調用需要複製:'redis.call('SADD',KEYS [1],id)'。 –