Вы можете сделать это действительно эффективно, на самом деле. Что ж, если вы не боитесь немного изменить макет таблицы по умолчанию в Rails, и если вы не боитесь генерировать свой собственный сырой SQL ...
Я предполагаю, что вы используете MySQL для своей базы данных (я не уверен, что другие БД поддерживают это): вы можете использовать INSERT ... ON DUPLICATE KEY UPDATE , чтобы сделать это .
Вам придется настроить таблицу подсчета, чтобы она заработала, хотя «по дублированному ключу» относится только к первичному ключу, и идентификатор Rails по умолчанию, который является просто произвольным числом, вам не поможет. Вам нужно изменить свой первичный ключ, чтобы он определял, что делает каждую запись уникальной - в вашем случае я бы сказал PRIMARY KEY(word, document_set_id)
. Это может не поддерживаться Rails по умолчанию, но есть по крайней мере один плагин и, возможно, еще пара, если вам не нравится этот.
Как только ваша база данных настроена, вы можете создать один гигантский оператор вставки и выбросить его в 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.
Надеюсь, это поможет!