我有
的以下代码h2.each {|k, v|
@count += 1
puts @count
sq.each do |word|
if Wordsdoc.find_by_docid(k).tf.include?(word)
sum += Wordsdoc.find_by_docid(k).tf[word] * @s[word]
end
end
rec_hash[k] = sum
sum = 0
}
h2 - >是一个包含文件ID的哈希,哈希包含超过1000个这样的哈希 Wordsdoc - >是我数据库中的模型/表格... sq - >是一个包含大约10个单词的哈希
我正在做的是我正在查看每个文档ID,然后对于sq中的每个单词,如果单词存在,则在Wordsdoc表中查找(Wordsdoc.find_by_docid(k).tf.include?(单词),这里tf是{word => value}
的散列如果是的话,我在Wordsdoc中获得该单词的值,并将其与@s中单词的值相乘,这也是{word =>的散列。值}
这似乎运行得很慢。 Tt每秒处理一个文档。有没有办法更快地处理?
非常感谢您对此的帮助!
答案 0 :(得分:2)
你做了很多重复的查询。虽然ActiveRecord可以在后台进行一些缓存以加快速度,但是它可以做什么是有限的,并且没有理由让它变得更难。
减速最明显的原因是Wordsdoc.find_by_docid(k)
。对于k
的每个值,您将其调用10次,每次调用它时都有可能再次调用它。这意味着您为h2
中的每个条目使用相同的参数调用该方法10-20次。对数据库的查询是昂贵的,因为数据库在硬盘上,并且在任何系统中访问硬盘都很昂贵。您可以在进入Wordsdoc.find_by_Docid(k)
循环之前轻松调用sq.each
一次,然后将其存储在变量中 - 这样可以节省大量查询并使循环变为更快。
另一个优化 - 虽然不如第一个那么重要 - 是在单个查询中获取所有Wordsdoc记录。几乎所有中高级(以及一些低级别的!)编程语言和库在批量处理时工作得更好更快,而且ActiveRecord也不例外。如果您可以查询Wordsdoc
的所有条目,并按docid
的{{1}}个键进行过滤,则可以转换1000个查询(之后)第一次优化。在第一次优化之前,它是10000-20000个查询)到一个巨大的查询。这将使ActiveRerocd和底层数据库能够以更大的块检索您的数据,并为您节省大量的光盘访问权。
你可以做一些小的优化,但我指定的两个应该绰绰有余。
答案 1 :(得分:1)
您正在拨打Wordsdoc.find_by_docid(k)
两次。
您可以将代码重构为:
wordsdoc = Wordsdoc.find_by_docid(k)
if wordsdoc.tf.include?(word)
sum += wordsdoc.tf[word] * @s[word]
end
......但它仍然是丑陋和低效的。
您应该批量预取所有记录,请参阅:https://makandracards.com/makandra/1181-use-find_in_batches-to-process-many-records-without-tearing-down-the-server
例如,类似的东西应该更有效率:
Wordsdoc.find_in_batches(:conditions => {:docid => array_of_doc_ids}).each do |wordsdoc|
if wordsdoc.tf.include?(word)
sum += wordsdoc.tf[word] * @s[word]
end
end
此外,您只能使用:select => :tf
方法中的find_in_batches
从Wordsdoc表中检索某些列。
答案 2 :(得分:0)
由于你有很多事情要做,我只是打算为你提供检查的东西。
inject
是一种方法,可以加快您sum
部分的目标。去找他们。