2012-04-25 27 views
1

我有使用哈希在Ruby中通过表迭代运行速度慢

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的散列,散列包含比这些 Wordsdoc 1000更多 - >是我的数据库中的模型/表格... sq - >是一个包含大约10个单词的散列

我在做什么是我要通过每个文档ID然后每个单词sq如果单词存在(Wordsdoc.find_by_docid(k).tf.include?(单词),我在Wordsdoc表中查找,这里tf是{word => value}的散列表

如果确实如此,我得到这个词的价值Wordsdoc并且与词的@s价值倍数它,这也是{字=>值}

这似乎是一个哈希运行非常慢。每秒处理一个文件。有没有办法更快地处理这个问题?

非常感谢您的帮助!

回答

0

由于你有很多事情要做,我只是要提供给你一些事情来检查。

  1. 一本名为Eloquent Ruby的书处理文档并遍历文档以统计单词的使用次数。他所有的例子都是关于他所维护的文档系统,所以它甚至可以为您解决其他问题。
  2. inject是一种方法,可能会加速您对sum部件的操作。
  3. 延迟工作整个事情,如果你这样做异步。这意味着如果这是一个网络应用程序,如果您在等待1000秒完成这项工作才能显示它在屏幕上的答案之前就必须超时。

去吧。

2

你做了很多重复的查询。虽然ActiveRecord可以在后台执行一些缓存以加快速度,但它可以执行的操作是有限制的,并且没有理由让它变得更难。

减速最明显的原因是Wordsdoc.find_by_docid(k)。对于k的每个值,您将其称为10次,并且每次调用它时都有可能再次调用它。这意味着您在h2中的每个条目都以相同的参数调用该方法10-20次。对数据库的查询很昂贵,因为数据库位于硬盘上,在任何系统中访问硬盘都很昂贵。在输入sq.each循环之前,您可以轻松地调用Wordsdoc.find_by_Docid(k)一次,并将其存储在一个变量中 - 这可以节省大量查询并使循环变得更快。

另一个优化虽然不像第一个那么重要,但它可以在单个查询中获得所有的Wordsdoc记录。几乎所有的中高级别(以及一些低级别!)编程语言和库在工作时都会更好更快地工作,ActiveRecord也不例外。如果您可以查询全部条目Wordsdoc,并通过的docid的键对它们进行过滤,则可以将1000个查询(在第一次优化之后,在第一次优化之前,它是10000-20000次查询)转换为单一的,巨大的查询。这将使ActiveRerocd和底层数据库能够以更大的块来检索您的数据,并为您节省大量的光盘访问。

还有一些更小的优化,你可以做,但我指定的两个应该是绰绰有余。

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 

您也可以使用例如由Wordsdoc表中检索只有某些列:select => :tffind_in_batches方法。