Ruby部分检索大量记录并迭代它们

时间:2013-05-11 12:26:17

标签: ruby-on-rails ruby collections iterator persistent-storage

我是Ruby的新手,但我在其他编程语言方面有很多经验。我需要迭代大量的记录(来自db或任何持久存储)。存储引擎允许我部分地按范围检索记录。在PHP中,我通常编写自定义迭代器,加载一系列记录迭代它们,当需要加载下一部分记录并忘记前一部分时。脚本内存使用与存储请求计数之间的一些权衡。像这样的东西(从评论here复制):

class Database_Result_Iterator {
...
private $_db_resource = null;
private $_loaded = false;
private $_valid = false;

function rewind() {
    if ($this->_db_resource) {
        mysql_free($this->_db_resource);
        $this->_db_resource = null;
    }
    $this->_loaded = false;
    $this->_valid = false;
}

function valid() {
    if ($this->_loaded) {
        $this->load();
    }
    return $this->_valid;
}

private function load() {
    $this->_db_resource = mysql_query(...);
    $this->_loaded = true;
    $this->next(); // Sets _valid
}

}

如何在Ruby中转换这种方法?即我有一些类 Voter 和方法 get_votes ,它返回所有投票属于当前投票者对象。可以检索不是具有所有投票的数组,但可以检索有可能迭代它的投票集合。我该如何实施呢?

更新

请不要将ActiveRecord和RDBMS视为一种可能的存储。那么Redis的存储和命令如LRANGE呢?我对常见的代码模式感兴趣,以解决Ruby中的这类问题。

3 个答案:

答案 0 :(得分:4)

来自Ruby on Rails上的guides

User.all.each do |user|
  NewsLetter.weekly_deliver(user)
end

非常无效。您可能希望在数据库中执行大部分过滤操作。 ActiveRecord为此提供了一个名为find_each的方法:

User.find_each(:batch_size => 5000) do |user|
  NewsLetter.weekly_deliver(user)
end

:batch_size参数允许获取数据切片而不是获取整个结果集。在大多数情况下非常有帮助。

但是,您可能不希望首先对所有记录进行操作:

User.with_newsletter.each do |user| 
   NewsLetter.weekly_deliver(user)
end

其中with_newsletter是所谓的scope

答案 1 :(得分:2)

我真的没有看到这个问题的重点。 AR是用于查询RDBMS的API,这就是您在AR中执行此操作的方法。

如果你想做redis,你必须自己在驱动程序级别编写它,或者为Redis找到类似的AR抽象...我认为DataMapper有一个redis适配器。 如果有一种通用的方法可以在任何数据存储中执行此操作,那么可能在DataMapper中,但创建自己的基本模式将是查看AR如何实现find_each / find_in_batches并为您选择的商店执行此操作。 / p>

答案 2 :(得分:1)

听起来您想使用find_eachhttp://apidock.com/rails/ActiveRecord/Batches/ClassMethods/find_each)。这使您可以通过加载一个小数字,迭代它们,然后加载到另一个批次等等来遍历大型数据集。

User.find_each do |user|
  user.do_some_stuff
end

将遍历所有用户,而不会立即将大量的内容加载到内存中。