1

要件は次のとおりです。

事実1:レガシーシステムによって生成されたデータファイルがいくつかあります

事実2:新しいシステムによって生成されたデータファイルがいくつかあり、最終的にはレガシーシステムを置き換える必要があります

事実3:

  1. どちらのファイルもテキスト/ASCIIファイルであり、レコードは複数の行で構成されています。
  2. レコード内の各行は、フィールド名とフィールド値で構成されます。
  3. 行が表示される形式は1と2で異なりますが、フィールド名とフィールド値は、正規表現を使用して各行から抽出できます。
  4. フィールド名は1から2の間で変更できますが、それらを関連付けるマッピングがあります
  5. 出力ファイル内のレコードの順序は両方のシステムで同じである必要はないため、各レコードには一意の識別子があり、レガシーレコードを新しいレコードに関連付けるのに役立ちます。
  6. 比較する各ファイルは、最低10 MBで、平均的なケースは30〜35MBです。

事実4:新しいシステムを構築することを繰り返すとき、まったく同じ条件下で両方のシステムによって生成されたファイルを比較し、違いを調整する必要があります。

事実5:この比較は、高価なビジュアル差分ツールを使用して手動で行われています。これを支援するために、2つの異なるフィールド名を共通の名前にし、各ファイルの各レコードのフィールド名を並べ替えて、順番に同期するツールを作成しました(新しいファイルには、で無視される余分なフィールドを含めることができます)視覚的な違い)

事実6:人間が手動で比較を行っていることと、人間がミスを犯していることにより、タイムラインに大きな影響を与える誤ったポーズとネガティブが発生しています。

明らかに問題は、「ALG」と「DS」はどうあるべきかということです。

私が対処しなければならないシナリオ:

人々がdiffを視覚的に検査し続ける場合、これでは、既存のスクリプトのパフォーマンスは悲惨です。ほとんどの処理は、行の配列を辞書式順序でソートすることであるようです(配列要素の読み取り/フェッチ:Tie :: File :: FETCH、Tie :: File :: Cache :: lookupを正しい場所に配置して、ソートされるようにします:Tie :: File :: Cache :: insert、Tie :: File :: Heap :: 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トライであると信じています、それで挿入自体で各レコードのフィールドはソートされます。したがって、最終的な配列を一度に並べ替える必要はなく、コストは償却されます(私の側の推測)

その場合、別の問題が発生します-Tie :: Fileは配列を使用してファイル内の行を抽象化します-行をツリーに読み込んでから、それらを配列にシリアル化すると、追加のメモリと処理が必要になります/

質問は-タイドアレイをソートする現在のコストよりもコストがかかるでしょうか?

4

1 に答える 1

2

Tie::File は非常に遅いです。これには 2 つの理由があります。第 1 に、同順位変数は標準変数よりも大幅に遅くなります。もう 1 つの理由は、Tie::File の場合、配列内のデータがメモリではなくディスク上にあることです。これにより、アクセスが大幅に遅くなります。Tie::File のキャッシュは、状況によってはパフォーマンスを向上させることができますが、ここで行っているように一度に 1 要素ずつ配列をループする場合はそうではありません。(キャッシュは、同じインデックスに再アクセスする場合にのみ役立ちます。) Tie::File を使用するのは、すべてのデータを一度にメモリに格納する必要があるアルゴリズムがあるが、そうするのに十分なメモリがない場合です。Tie::File を使用して一度に 1 行ずつファイルを処理しているだけなので、無意味であるだけでなく、有害です。

ここでのトライは正しい選択ではないと思います。代わりにプレーンな HoH (ハッシュのハッシュ) を使用します。ファイルが小さいので、すべてを一度にメモリに格納できるはずです。各ファイルを解析し、次のようなハッシュを作成することをお勧めします。

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

データ構造の構築中にマッピングを使用してフィールド名を正規化すると、比較が容易になります。

データを比較するには、次のようにします。

  1. 2 つのハッシュのキーのセット比較を実行します。これにより、レガシー データのみに存在する ID、新しいデータのみに存在する ID、および両方に存在する ID の 3 つのリストが生成されます。
  2. 1 つのデータ セットにのみ表示される ID のリストを報告します。これらは、他のデータ セットに対応するレコードがないレコードです。
  3. 両方のデータ セットの ID について、各 ID フィールドのデータをフィールドごとに比較し、相違点を報告します。
于 2009-05-21T02:59:19.800 に答える