2009-05-20 14 views
1

的要求是:比較在文件中的記錄和報告統計 - 場景1

事實1:我們有一個遺留系統產生的一些數據文件

事實2:我們有一個新產生了一些數據文件系統應最終取代傳統的一個

事實3:

  1. 這兩個文件是文本/ ASCII文件, 與記錄被由 多行。
  2. 記錄中的每行包含字段名稱和字段值的 。
  3. 的格式,其中所述線是 呈現是1 和2,但字段名和fieldValue方法 可以從每個線 通過使用正則表達式來提取
  4. 字段名稱可以在1和 2之間變化,但之間不同我們有一個影射 涉及他們
  5. 每個記錄有一個唯一的標識符 ,幫助我們用新的記錄涉及遺留 記錄在輸出文件排序記錄 需要 不能在兩個系統相同。
  6. 每個文件進行比較是最低的 10 MB到30的平均情況 - 35 MB

事實4:當我們在這迭代雖然建立新的系統,我們需要比較由兩個系統在完全相同的條件下生成的文件並調和差異。

事實5:此比較是使用昂貴的視覺差異工具手動完成的。爲了解決這個問題,我編寫了一個工具,將兩個不同的字段名變成一個通用名稱,然後對每個文件中每個記錄中的字段名進行排序,以便它們按順序同步(新文件可以包含額外的字段,視覺差異)

事實6:由於比較是由人工手動完成的,而且人爲犯錯誤,所以我們得到的虛假姿勢和負面影響顯着影響了我們的時間表。

顯然問題是,'ALG'和'DS'應該是什麼?

我不得不解決的方案:

在那裏,人們不斷地目視檢查存在 - 在這方面,exsiting腳本的性能是令人沮喪的 - 大部分的處理似乎是在分揀線的陣列字典順序(讀取/讀取數組元素:Tie :: File :: FETCH,Tie :: File :: Cache :: lookup並將它放在正確的位置,以便對它進行排序:Tie :: File :: Cache :: insert,領帶::文件::堆::插入)

use strict; 
use warnings; 

use Tie::File; 

use Data::Dumper; 

use Digest::MD5 qw(md5_hex); 

# open an existing file in read-only mode 
use Fcntl 'O_RDONLY'; 

die "Usage: $0 <unsorted input filename> <sorted output filename>" if ($#ARGV < 1); 

our $recordsWrittenCount = 0; 
our $fieldsSorted = 0; 

our @array; 

tie @array, 'Tie::File', $ARGV[0], memory => 50_000_000, mode => O_RDONLY or die "Cannot open $ARGV[0]: $!"; 

open(OUTFILE, ">" . $ARGV[1]) or die "Cannot open $ARGV[1]: $!"; 

our @tempRecordStorage =(); 

our $dx = 0; 

# Now read in the EL6 file 

our $numberOfLines = @array; # accessing @array in a loop might be expensive as it is tied?? 

for($dx = 0; $dx < $numberOfLines; ++$dx) 
{ 
    if($array[$dx] eq 'RECORD') 
    { 
     ++$recordsWrittenCount; 

     my $endOfRecord = $dx; 

     until($array[++$endOfRecord] eq '.') 
     { 
      push @tempRecordStorage, $array[$endOfRecord]; 
      ++$fieldsSorted; 
     } 

     print OUTFILE "RECORD\n"; 

     local $, = "\n"; 
     print OUTFILE sort @tempRecordStorage; 
     @tempRecordStorage =(); 

     print OUTFILE "\n.\n"; # PERL does not postfix trailing separator after the last array element, so we need to do this ourselves) 

     $dx = $endOfRecord;  
    } 
} 

close(OUTFILE); 

# Display results to user 

print "\n[*] Done: " . $fieldsSorted . " fields sorted from " . $recordsWrittenCount . " records written.\n"; 

所以我想過這個問題,我相信,某種如果特里,也許後綴特里/ PATRICIA線索,以便在插入itsel f每個記錄中的字段都被排序。 因此,我不必一次性排序最後一個數組,並且成本將被攤銷(我的猜測)

在這種情況下出現另一個問題 - Tie :: File使用數組來抽象行一個文件 - 將行讀入一棵樹,然後將它們序列化回數組需要額外的內存和處理/

問題是 - 這會花費比排序綁定數組的當前成本更多嗎?

回答

2

Tie :: File很慢。有兩個原因:首先,綁定變量顯着慢於​​標準變量。另一個原因是,在Tie :: File的情況下,數組中的數據在磁盤上而不是在內存中。這大大減緩了訪問。 Tie :: File的緩存可以幫助某些情況下的性能,但不是像在這裏一樣只是一次一個數組地循環數組。 (只有當你重新訪問相同的索引時,緩存纔有幫助。)使用Tie :: File的時間是當你有一個算法需要同時在內存中存儲所有的數據,但你沒有足夠的內存去做。由於您只使用Tie :: File一次只處理一行文件,這不僅毫無意義,而且也是有害的。

我不認爲一個trie是在這裏正確的選擇。我會使用一個普通的HoH(哈希散列)。您的文件足夠小,以至於您應該能夠一次將所有內容都放入內存中。如果您使用的映射,同時建立數據結構就會使比較容易標準化的字段名

%data = (
    id1 => { 
    field1 => value1, 
    field2 => value2, 
    }, 
    id2 => { 
    field1 => value1, 
    field2 => value2, 
    }, 
); 

:我建議解析每個文件建立一個哈希看起來像這樣。

的數據進行比較,這樣做:

  1. 執行兩個散列的鍵的一組比較。這應該生成三個列表:僅存在於舊數據中的ID,僅存在於新數據中的ID以及存在於兩者中的ID。
  2. 報告僅出現在一個數據集中的ID列表。這些是在其他數據集中沒有相應記錄的記錄。
  3. 對於兩個數據集中的ID,請按字段比較每個ID字段的數據並報告任何差異。