1

私は次のコードを持っています

h2.each {|k, v|
   @count += 1
   puts @count
   sq.each do |word|
       if Wordsdoc.find_by_docid(k).tf.include?(word)
       sum += Wordsdoc.find_by_docid(k).tf[word] * @s[word]
       end
     end
   rec_hash[k] = sum
   sum = 0
   }

h2->はドキュメントのIDを含むハッシュであり、ハッシュには1000を超えるこれらのWordsdocが含まれています->は私のデータベースのモデル/テーブルです...sq->は約10語を含むハッシュです

私がやっていることは、各ドキュメントIDを調べてから、sq内の各単語について、その単語が存在するかどうかをWordsdocテーブルで検索することです(Wordsdoc.find_by_docid(k).tf.include?(word)、ここで、tfは{word=>value}のハッシュです。

もしそうなら、Wordsdocでその単語の値を取得し、それを@sの単語の値と乗算します。これは、{word=>value}のハッシュでもあります。

これは非常に遅いようです。Ttは1秒あたり1つのドキュメントを処理します。これをより速く処理する方法はありますか?

これについてあなたの助けに本当に感謝します!

4

3 に答える 3

2

多くの重複したクエリを実行します。ActiveRecord は処理を高速化するためにバックグラウンドでキャッシュを実行できますが、実行できることには制限があり、処理を難しくする理由はありません。

減速の最も明白な原因はWordsdoc.find_by_docid(k). の値ごとkに 10 回呼び出し、呼び出すたびに再度呼び出す可能性があります。つまり、 の各エントリに対して、同じ引数を使用してそのメソッドを 10 ~ 20 回呼び出すことになりh2ます。データベースはハード ディスク上にあり、どのシステムでもハード ディスクへのアクセスにはコストがかかるため、データベースへのクエリにはコストがかかります。ループに入る前にWordsdoc.find_by_Docid(k) 一度呼び出して変数に格納するのと同じくらい簡単にできますsq.each。これにより、多くのクエリが節約され、ループがはるかに高速になります。

別の最適化 (最初のものほど重要ではありませんが) は、1 つのクエリですべての Wordsdoc レコードを取得することです。ほぼすべての中レベルから高レベル (および一部の低レベルも!) のプログラミング言語とライブラリは、まとめて使用するとより適切に高速に動作します。ActiveRecord も例外ではありません。のすべてのエントリをクエリし、 のキーでそれらをフィルタリングできる場合、Wordsdoc1000クエリ (最初の最適化後。最初の最適化前は 10000 ~ 20000 クエリ) を単一の巨大なクエリに変えることができます。これにより、ActiveRerocd と基盤となるデータベースがデータをより大きなチャンクで取得できるようになり、ディスク アクセスを大幅に節約できます。docidh2

実行できる小さな最適化がいくつかありますが、指定した 2 つで十分です。

于 2012-04-25T10:51:32.373 に答える
1

あなたはWordsdoc.find_by_docid(k)2回電話しています。

コードを次のようにリファクタリングできます。

wordsdoc = Wordsdoc.find_by_docid(k)
if wordsdoc.tf.include?(word)
  sum += wordsdoc.tf[word] * @s[word]
end

...しかし、それでも醜く非効率的です。

すべてのレコードをバッチでプリフェッチする必要があります。https ://makandracards.com/makandra/1181-use-find_in_batches-to-process-many-records-without-tearing-down-the-server を参照してください。

たとえば、次のようなものの方がはるかに効率的です。

Wordsdoc.find_in_batches(:conditions => {:docid => array_of_doc_ids}).each do |wordsdoc|
  if wordsdoc.tf.include?(word)
    sum += wordsdoc.tf[word] * @s[word]
  end
end

また、たとえば:select => :tfinfind_in_batchesメソッドを使用して、Wordsdoc テーブルから特定の列のみを取得することもできます。

于 2012-04-25T11:19:19.800 に答える
0

たくさんのことが起こっているので、私はあなたにチェックアウトするものまで提供するつもりです.

  1. Eloquent Rubyという本では、ドキュメントと、ドキュメントを繰り返し処理して単語が使用された回数を数えています。彼の例はすべて、彼が保守していたドキュメント システムに関するものであり、他の問題にも対処できる可能性があります。
  2. injectsumおそらく、その部分でやりたいことをスピードアップできる方法です。
  3. これを非同期で実行している場合、遅延ジョブ全体。つまり、これが Web アプリの場合、このジョブが完了するのを 1000 秒待ってから画面に回答が表示される場合は、タイムアウトしている必要があります。

取りに行く。

于 2012-04-25T10:49:34.923 に答える