我会尽力解释我的问题。 我创建了一个表,它表示基于购买的用户 (user_models) 之类的文本模型。我还有一个表 term_tfs,它将 user_id 和 term(varchar(200)) 存储为 PK 以及一些其他数字列。它基本上是一个矩阵,其中包含术语及其模型的数字 tf_idf_norm 值。现在我需要进行比较用户模型的计算,所以我需要为一个用户加载这个矩阵,并与不同用户的其他矩阵进行比较。
问题是,term_tfs 表真的很大(大约 13.5 行),我需要为至少有 5 次(1285 位用户)或 10 次(9333)购买的用户获取矩阵。当我从 term_tfs 表中进行选择时,大约需要 20-40 毫秒。但是我需要一些方法来让其他 9000 名用户进行比较。将每个 user_id 查询到 term_tfs 中的天真的方法需要 10 秒以上的时间进行一次比较,如果我想为接下来的几千个用户进行这种比较并将其存储在其他地方,这会很慢。
def self.compare_user(user_id)
@results = Hash.new
# @user_ids = UserModel.where.not(user_id: user_id).pluck(:user_id)
@user_ids = UserModel.get_useful_ids(user_id, 5)
@user_matrix = TermTf.where(user_id: user_id).pluck(:term, :tf_idf_norm)
@user_terms = @user_matrix.map { |a| a[0] }
@user_ids.each do |id|
matrix = TermTf.where(user_id: id).pluck(:term, :tf_idf_norm)
store_result( compare_matrix(matrix), id )
end
sort_results( @results )
end
def self.compare_matrix(matrix)
sim = 0
matrix.each do |t|
unless ( ( i = @user_terms.index(t[0]) ).nil? )
sim += t[1] * @user_matrix[i][1]
end
end
sim
end
def self.store_result(similarity, id)
@results[id] = similarity
end
基准输出(9333 user_ids):
puts Benchmark.measure {@user_ids.each{|id| TermTf.where(user_id: id).pluck(:term, :tf_idf_norm)}}
4.890000 0.180000 5.070000 ( 11.019708)
这似乎是一种相当糟糕/缓慢的方法,那么如何让它更快呢?我很想听听其他解决这个问题的方法,比如使用 Ruby 或 SQL。
最佳答案
要将 Beartech 的方法放入 Rails 代码而不是创建 View ,您可以这样做(需要根据您的需要进行调整):
subquery = TermTf.where(user_id: user_id).select(:term, :tf_idf_norm).to_sql
result = TermTf.joins("INNER JOIN (#{subquery }) sub on sub.term = term_tfs.term")
.select("term_tfs.user_id as user_id, sum(sub.tf_idf_norm * term_tfs.tf_idf_norm) as tf_idf_norm_sum")
.where(user_id: @user_ids)
.where.not(user_id: user_id)
.group('term_tfs.user_id')
.all
关于ruby-on-rails - 大表上的 Rails 计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40918735/