2012-04-25 28 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方法。