2012-01-03 33 views
8

我必須通過組合兩個不同的文件來處理一些數據。他們兩個都有兩列,可以組成一個主鍵,我可以用它們並排匹配它們。問題中的文件很大(大約5GB,2000萬行),所以我需要一個高效的代碼。我將如何在Perl中執行此操作?如何在Perl中執行類似SQL的加入?

我舉一個例子:

如果文件中包含列

id, name, lastname, dob, school 

文件B包含列

address, id, postcode, dob, email 

我需要通過匹配ID來加入這兩個文件dob在兩個文件中有一個輸出文件,該文件具有列:

id, name, lastname, dob, school, address, postcode, email 
+1

你有多少RAM? – 2012-01-09 19:49:58

回答

8

想想我會創建一個新的mysql/sqlite /任何數據庫並插入行。應該是~20行perl。

這當然需要方便地訪問DB ..

猜你還可以將文件通過有趣的字段進行排序,然後在文件1的每一行查找和file2中打印匹配點。

+1

大多數發行版都有sqlite模塊.. – shaun5 2012-01-03 14:12:39

+2

...您可以直接從CPAN(DBD :: SQLite)構建SQLite的副本。順便說一句,在將大量數據插入到SQLite時,請注意使用大型事務。 – tsee 2012-01-04 17:54:10

0

或者,仔細閱讀這篇文章Techrepublic文章 - 儘管如此,您仍然需要5G的內存。我想知道在哪裏使用unix/linux CLI排序/加入實用程序將效率。只是一個想法。

2

這樣做的老式方法是使用系統實用程序按鍵序列對兩個文件進行排序,然後逐行匹配它們。如果鍵匹配輸出數據,則讀取這兩個文件。如果它們不匹配,請使用較小的密鑰讀取文件,直到它們匹配。如果文件遇到eof,請將文件的密鑰設置爲無限高。當兩個鍵都無限高時,你就完成了。

+0

如果對輸入進行排序,系統實用程序'join'甚至會爲您執行連接。 – reinierpost 2012-01-09 14:27:20

+0

太棒了,不知道。謝謝。 – 2012-01-09 16:34:19

0

我還沒有真正嘗試過這一點,但更創造性的解決方案可能是:

  1. 閱讀每個文件一次,並且創建的唯一ID + DOB組合及其在文件中的位置之間的映射。使用tell()
  2. 在Perl中創建
  3. 地圖閱讀使用位置的文件的實際數據詮釋,他的地圖和sysread()
  4. 將數據寫入到一個新文件
0

您也可以使用我的3年-old CPAN模塊Set :: Relation旨在執行此類操作,讓您執行所有SQL功能,例如在Perl中加入。爲每個文件創建一個Set :: Relation對象,然後使用join()方法。也就是說,這個實現的模塊將保留所有的操作數並導致內存,所以它受RAM的限制。但是你仍然可以看看join()的工作原理,然後根據它爲你的目的實現一個更高效的版本。