2013-01-11 46 views
0

所以我得到了這些巨大的文本文件,每行用單個逗號分隔的記錄填充。我需要一種逐行處理文件的方法,刪除滿足特定條件的行。一些清除很容易,比如其中一個字段小於一定長度。最難的標準是這些線都有時間戳。除了時間戳以外,許多記錄都是相同的,我必須刪除所有記錄,但只能刪除相同的記錄,並且在15秒之內。使用時間戳處理百萬行文件的最快方法

所以我想知道如果其他人可以想出最好的辦法。我確實想出了一個用Java完成任務的小程序,使用JodaTime獲取時間戳,這使得它非常簡單。但是,我編寫程序的最初方式是進入OutofMemory堆空間錯誤。我對代碼進行了一些重構,大多數情況下它似乎沒問題,但我仍然認爲它有一些內存問題,有時候這個程序似乎會被掛掉。這和它似乎太長了。我不確定這是一個內存泄漏問題,一個糟糕的編碼問題,或者其他的問題。是的,我試圖顯着增加堆大小,但仍然有問題。

我會說程序需要Perl或Java。我也許能夠使python腳本也能工作,但我不太熟悉python。正如我所說的,由於JodaTime庫,Java中的時間戳對於我來說是最簡單的。我不知道如何在Perl中完成時間戳記。但我渴望學習和使用最好的方法。

我還將添加正在讀取的文件大小差異很大,但一些大的文件大約100Mb,有130萬條記錄。

我的代碼實質上是讀入所有記錄,並將它們放入一個Hashmap中,這些鍵是相似記錄將共享的記錄中數據的特定子集。所以記錄的一個子集不包括時間戳將會不同。這樣你最終會得到一些數據相同的記錄,但發生在不同的時間。 (如此完全相同減去時間戳)。

然後,每個鍵的值是一組具有相同數據子集的記錄。然後我簡單地遍歷Hashmap,獲取每個集合並遍歷它。我將第一條記錄與其他時間進行比較,看看它們是否在15秒內。如果是這樣的記錄被刪除。一旦該設置完成,它會寫入文件,直到所有記錄都已經過。希望這是有道理的。

這很有效,但很明顯,我這樣做的方式太過記憶密集。任何人有更好的方式來做到這一點的任何想法?或者,我可以在Perl中執行此操作的方式實際上是好的,因爲嘗試將Java程序插入到當前實現中會導致其他一些令人頭痛的問題。雖然也許這只是因爲我的記憶問題和糟糕的編碼。

最後,我並沒有要求別人爲我寫程序。僞代碼很好。儘管如果你有Perl的想法,我可以使用更多細節。我不知道如何在Perl中做的主要是時間比較的東西。我已經看了一些Perl庫,但沒有看到任何像JodaTime(儘管我沒有看太多)。任何想法或建議表示讚賞。謝謝。

+4

請在您的日誌文件中顯示幾行。 – Borodin

+1

你不能假設線路是爲了?您是否有任何理由需要保留超過15秒的記錄,或只保留以前的記錄? –

+0

是否按時間戳排序?如果是這樣,那麼你只需要一次在內存中擁有15秒鐘的行。如果沒有,你可能想排序行 - 然後任務變得更容易。與其將所有內容加載到內存中,您可能會考慮使用時間戳對它們進行排序的方法,然後使用狀態機遍歷排序的文件併發出時間戳的最後一行。你也可以考慮將它們倒入mongodb中,因爲那樣它們會更容易處理。但100Mb文件並不大。 – Rob

回答

4

讀取所有行並不理想,因爲您需要將整個存儲區存儲在內存中。

取而代之,您可以逐行閱讀,寫出您希望保留的記錄。您可以保留先前命中的行的緩存,限制在當前程序的15秒內。在非常粗糙的僞代碼,每一行你閱讀:

var line = ReadLine() 
DiscardAnythingInCacheOlderThan(line.Date().Minus(15 seconds); 
if (!cache.ContainsSomethingMatchingCriteria()) { 
    // it's a line we want to keep 
    WriteLine(line); 
} 

UpdateCache(line); // make sure we store this line so we don't write it out again. 

正如指出的那樣,這種假設線在時間戳順序。如果它們不是,那麼我只是使用UNIX sort來實現它,因爲它會很高興地處理非常大的文件。

+0

我不知道排序功能。我得看看那個。謝謝。 – cardician

0

您可能只讀取了文件並輸出了要刪除的行號(要在單獨的過程中進行排序和使用)。然後,您的哈希映射只能包含所需的最小數據和行號。如果所需數據與線路大小相比較小,這可以節省大量內存。

相關問題