草庐IT

lua - 从 Redis 集中过滤/删除项目

coder 2023-07-19 原文

我将公交车站到达时间和路线 ID 缓存在一个 Redis 集合中,每个公交车站一组。我正在寻找一种简单的方法来更新这些集合,删除过去的到达时间,同时保留任何其他 future 的到达时间。如何在写入时根据特定条件过滤集合?

有一段时间没有写入的集会过期,所以我只关心不断更新的集,本质上是在元素级别而不是集级别设置过期。

最佳答案

以下将过滤掉小于 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
}

脚本采用以下参数:

  • “ key ”
    • 设置要更新的 key
    • 当前 UNIX 时间戳(无法从 Redis 内部访问,因此需要从外部传递)
  • 值(value)观
    • 格式为[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] 读取/修改的key
  4. KEYS[2] 当前 UNIX 时间戳
  5. (及以上)VALUES 要添加到集合中的任何新值

关于lua - 从 Redis 集中过滤/删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35677682/

有关lua - 从 Redis 集中过滤/删除项目的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  3. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  4. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  5. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  6. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  7. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  8. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  9. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  10. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

随机推荐