2011-02-07 8 views
0

私のレールアプリでは、用語(キーワード)と特定のドキュメントセットに表示される頻度整数)。新しい文書がセットに追加されるたびに、単語を解析し、新しい用語とその頻度を用語表に挿入するか、既存の用語の頻度を更新する必要があります。Rails - 新しいデータを挿入する、または更新すると既存の値をインクリメントする

これを行う最も簡単な方法は、findを実行することです。次に空の場合は挿入を行い、空でない場合は、既存のレコードの頻度を正しい量だけ増やします。しかし、それは1語につき2つの質問ですが、単語数が多い文書は奇妙なほど長い質問のリストになります。これを行うより効率的な方法はありますか?

+0

あなた自身の質問に答えています。あなたが何をしても、単語ごとに検索と作成/更新が常に必要になります。 – nunopolonia

答えて

1

これは本当に効率的に行うことができます。もしあなたがRailsのデフォルトのテーブルレイアウトを微調整するのを恐れていないなら、あなた自身の生のSQLを生成することを恐れていなければ...

私はあなたのためにMySQLを使用していると仮定しますデータベース(他のDBがこれをサポートしているかどうか不明):INSERT ... ON DUPLICATE KEY UPDATEを使ってこれを行うことができます。

"重複キーで"はプライマリキーのみを参照し、RailsのデフォルトIDは任意の数値であり、あなたの手助けにはなりませんが、カウントテーブルを調整する必要があります。あなたのプライマリキーを変更して、各レコードをユニークにするものを識別できるようにする必要があります。あなたのケースでは、私はPRIMARY KEY(word, document_set_id)と言います。これはデフォルトではRailsではサポートされていないかもしれませんが、少なくとも1つのpluginがあります。

データベースが設定されたら、1つの巨大なinsert文を作成してMySQLに投げて、クエリの "重複したキー"部分があなたのために厄介な存在チェックをするようにすることができます(注:そこにも、バッチ挿入を行うためのプラグインがありますが、私はドン; tは、彼らがどのように動作するかを知っている - )、特に「重複キーオン」に関してで:

counts = {} 
#This is just demo code! Untested, and it'll leave in punctuation... 
@document.text.split(' ').each do |word| 
    counts[word] ||= 0 
    counts[word] += 1 
end 

values = [] 
counts.each_pair do |word, count| 
    values << ActiveRecord::Base.send(:sanitize_sql_array, [ 
     '(?, ?, ?)', 
     word, 
     @document.set_id, 
     count 
    ]) 
end 

#Massive line - sorry... 
ActiveRecord::Base.connection.execute("INSERT INTO word_counts (word, document_set_id, occurences) VALUES ${values.join(', ')} ON DUPLICATE KEY UPDATE occurences = occurences + VALUES(occurences)") 

そして、それはそれを行うだろう - のための1つのSQLクエリ新しい文書全体。はるかに速く、半分はあなたが1つのクエリだけを実行しているため、半分はActiveRecordの遅いクエリ構築を回避したためです。

希望に役立ちます!

関連する問題