2011-02-07 114 views
0

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

最简单的方法是做一个查找,然后如果它是空的做一个插入,或者如果它不是空的,按正确的数量增加现有记录的频率。然而,每个单词有两个查询,并且具有高字数的文档将导致查询的长度很长。有没有更有效的方法来做到这一点?

+0

您正在回答你自己的问题。无论你做什么,你总是需要一个查找和创建/更新每个单词。 – nunopolonia 2011-02-07 01:30:13

回答

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的缓慢查询构建。

希望有帮助!