1

私は Ruby の初心者ですが、他のプログラミング言語の経験は豊富です。大量のレコード(dbまたは永続ストレージから)を反復処理する必要があります。ストレージ エンジンを使用すると、範囲ごとに部分的にレコードを取得できます。PHPでは、通常、レコードの範囲をロードしてそれらを反復し、必要に応じてレコードの次の部分をロードし、前の部分を忘れるカスタムイテレータを作成します。スクリプトのメモリ使用量とストレージへのリクエスト数の間のトレードオフ。このようなもの(ここのコメントからコピー):

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 を 1 つのストレージとして考えないでください。また、ストレージとしての Redis と LRANGE のようなコマンドはどうでしょうか? Rubyでこの種の問題を解決するための共通のコードパターンに興味があります。

4

3 に答える 3

4

Ruby on Railsのガイドから:

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いわゆるスコープはどこにありますか。

于 2013-05-11T12:33:37.310 に答える
2

この質問のポイントが本当にわかりません。AR は RDBMS を照会するための API であり、それが AR での実行方法です。

redis を実行したい場合は、ドライバー レベルで自分で作成するか、Redis 用の AR と同様の抽象化を見つける必要があります... DataMapper には redis アダプターがあったと思います。任意のデータ ストアに対してこれを行う普遍的な方法がある場合は、おそらく DataMapper にありますが、独自のデータ ストアを作成するときに従うべき基本的なパターンは、AR がどのように find_each/find_in_batches を実装しているかを調べ、選択したストアに対してそれを行うことです。

于 2013-05-11T13:16:30.727 に答える
1

使いたいようですねfind_each( http://apidock.com/rails/ActiveRecord/Batches/ClassMethods/find_each )。これにより、少数のデータセットをロードし、それらを反復処理してから、別のバッチにロードするなどして、大規模なデータセットを反復処理できます。

User.find_each do |user|
  user.do_some_stuff
end

膨大な数のユーザーを一度にメモリにロードすることなく、すべてのユーザーを反復処理します。

于 2013-05-11T12:32:47.200 に答える