2016-02-28 136 views
1

我在Redis集中緩存公交車站到達時間和路由ID,每個公交車站一組。我正在尋找一種簡單的方法來更新這些設置,消除過去的到達時間,同時保留其他未來的到達時間。如何在寫入時根據特定標準過濾一組?從Redis集中過濾/刪除項目

一段時間以來一直未寫入的集合將過期,因此我只關注不斷更新的集合,實質上是在元素級別而不是集合級別設置到期。

回答

2

以下內容將過濾掉小於KEYS[2]的值(在我的情況下是UNIX時間戳,因爲Redis中的LUA腳本無法訪問日期/時間信息)。第二個子句然後添加傳遞給腳本的任何附加值。

local members_expired = 0 -- number of members expired/removed 
local additions_attempted = 0 -- number of SADD attempts 
local members_added = 0 -- number of members successfully added 
local key = KEYS[1] -- the key of the set to update 
local current_time = KEYS[2] -- the current timestamp 

-- iterate through existing members and "expire" (remove) any members 
-- less than the current time 
for index, value in next, redis.call('SMEMBERS', key) do 
    -- interpret the first 10 characters of the member as a timestamp, 
    -- allowing us to include additional data such as the route ID 
    if string.sub(value, 1, 10) < current_time then 
     redis.call('SREM', key, value); 
     members_expired = members_expired + 1 
    end 
end 

-- iterate through provided members and attempt to insert them into the 
-- target set 
for index, value in next, ARGV do 
    additions_attempted = additions_attempted + 1 
    members_added = members_added + redis.call('SADD', key, value) 
end 

-- number of duplicate members 
local duplicates_ignored = additions_attempted - members_added 

-- entire set will expire in 1 week unless it's updated in the meantime 
redis.call('EXPIRE', key, 604800) 

return { 
    members_added, 
    members_expired, 
    duplicates_ignored 
} 

腳本採用以下參數:

  • 「鑰匙」
    • 組關鍵更新
    • 當前Unix時間戳(不是從內部Redis的訪問,因此必須從外面通過)
  • 值 個
    • 的一個或多個格式[timestamp]:[extra_data]值,例如1474904925:route_123

它返回具有以下值的數組:

  1. 添加到該組的元素的數量。
  2. 帶有時間戳的元素的數量從集合中移除。
  3. 失敗插入的次數,推定爲已經在集合中重複。

PHP示例(使用Predis):

$predis = new Predis\Client(); 
$time = time(); 

// some time in the future to add to the set 
$values = [ 
    ($time + 3600) . ':route_123', 
    ($time + 7200) . ':route_123', 
    ($time + 7200) . ':route_456', 
    ($time + 7200) . ':route_456', // this is a duplicate 
]; 

$filter_script = <<<LUA 
local members_expired = 0 -- number of members expired/removed 
local additions_attempted = 0 -- number of SADD attempts 
local members_added = 0 -- number of members successfully added 
local key = KEYS[1] -- the key of the set to update 
local current_time = KEYS[2] -- the current timestamp 

-- iterate through existing members and "expire" (remove) any members 
-- less than the current time 
for index, value in next, redis.call('SMEMBERS', key) do 
    -- interpret the first 10 characters of the member as a timestamp, 
    -- allowing us to include additional data such as the route ID 
    if string.sub(value, 1, 10) < current_time then 
     redis.call('SREM', key, value); 
     members_expired = members_expired + 1 
    end 
end 

-- iterate through provided members and attempt to insert them into the 
-- target set 
for index, value in next, ARGV do 
    additions_attempted = additions_attempted + 1 
    members_added = members_added + redis.call('SADD', key, value) 
end 

-- number of duplicate members 
local duplicates_ignored = additions_attempted - members_added 

-- entire set will expire in 1 week unless it's updated in the meantime 
redis.call('EXPIRE', key, 604800) 

return { 
    members_added, 
    members_expired, 
    duplicates_ignored 
} 
LUA; 

// We can run the script directly... 
list($members_added, $members_expired, $duplicates_ignored) = $predis->eval(
    $filter_script, 
    2, 
    'somekey', 
    $time, 
    $values[0], 
    $values[1], 
    $values[2], 
    $values[3] 
); 

echo "Members added: $members_added\n"; 
echo "Members expired: $members_expired\n"; 
echo "Duplicate members ignored: $duplicates_ignored\n"; 
echo "\n"; 

// or save it for faster execution if we're going to run repeatedly 
$members_added_total = 0; 
$members_expired_total = 0; 
$duplicates_ignored_total = 0; 
$filter_script_sha = $predis->script('LOAD', $filter_script); 

foreach ($values as $value) { 
    list($members_added, $members_expired, $duplicates_ignored) = 
     $predis->evalsha($filter_script_sha, 2, 'somekey', $time, $value); 

    echo "[$members_added, $members_expired, $duplicates_ignored]\n"; 

    $members_added_total += $members_added; 
    $members_expired_total += $members_expired; 
    $duplicates_ignored_total += $duplicates_ignored; 
} 

echo "Members added: $members_added_total\n"; 
echo "Members expired: $members_expired_total\n"; 
echo "Duplicate members ignored: $duplicates_ignored_total\n"; 

參數evalevalsha是:

  1. 腳本或SHA1哈希,分別
  2. 始終爲 「2」(數量的參數傳遞給KEYS LUA變量 - 請參閱docs
  3. KEYS[1]讀取密鑰/修改
  4. KEYS[2]當前UNIX時間戳
  5. (以上)VALUES任何新值添加到集合