Rails - 插入新数据,或通过更新增加现有值

时间:2011-02-07 00:56:50

标签: ruby-on-rails parsing insert

在我的rails应用程序中,我有一个“术语”模型,它存储术语(关键字),以及它在特定文档集中出现的频率(整数)。每当新文档被添加到集合中时,我会解析单词,然后我需要在术语表中插入新术语及其频率,或者我需要更新现有术语的频率。

执行此操作的最简单方法是执行查找,如果它为空,则执行插入操作,或者如果它不为空,则将现有记录的频率增加正确的数量。然而,这是每个单词的两个查询,具有高字数的文档将导致一个非常长的查询列表。有没有更有效的方法来做到这一点?

1 个答案:

答案 0 :(得分:1)

实际上,你可以非常有效地做到这一点。好吧,如果你不害怕调整Rails的默认表格布局,如果你不害怕生成自己的原始SQL ......

我将假设您正在使用MySQL作为您的数据库(我不确定其他数据库是否支持此功能):您可以使用INSERT ... ON DUPLICATE KEY UPDATE来执行此操作。

你必须调整你的计数表以使其工作,但是 - “在重复键上”只引用主键,而Rails的默认ID,这只是一个任意数字,对你没有帮助。您需要更改主键,以便识别每条记录的唯一性 - 在您的情况下,我会说PRIMARY KEY(word, document_set_id)。默认情况下,Rails可能不支持这种情况,但如果你不喜欢那个,那么至少有一个plugin,可能还有一个。

一旦你的数据库被设置好了,你就可以建立一个巨大的插入语句,并把它扔到MySQL,让查询的“重复键”部分为你处理讨厌的存在检查(注意:那里也是插件来进行批量插入,但我不知道它们是如何工作的 - 特别是关于“在重复键上”):

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)")

这就是它 - 为整个新文档提供一个SQL查询。应该快得多,一半因为你只运行一个查询,一半是因为你已经回避了ActiveRecord缓慢的查询构建。

希望有所帮助!