2017-11-06 9 views
2

ソースファイルからコンテンツに基づいて異なるファイルに行を再配布するために使用される(G | M)awkスクリプトがあります。一例は、ソース・データのセットを行のタイム・スタンプに基づいて別々の日付付きファイルにシャーディングすることです。Awk getlineは徐々に時間がかかります

私はcsvヘッダー行を追加する必要があるまで十分に速いです。ソースデータは順不同ですので、if (getline < (fname) < 0) { print cols > fname }を使用して、最初のタッチ時にヘッダー行を含む各宛先ファイルを作成することを検討しました。

ソースデータの各行についてこのテストが高価になる可能性がありますが、宛先ファイルが作成されると、処理されるソースファイルの速度が遅くなるため、各getlineテストに時間がかかります。減速はパフォーマンス上の問題です。

このプロセスもGNU並列で実行されるため、system -fテストはシステムコールでハングしません。

ヘッダーを含むファイルを作成する際のパフォーマンスを改善する方法についての提案はありますか?他のロジックが既にあるので、このスクリプトをAwkに保存しておきたい。


タスクの例として、私は、ログエントリの日付に基づいてファイルに結合する必要があり、複数のホストからのログを持っている:

date, time, measure 
2017-01-01, 00:00, 10 
2017-01-01, 01:00, 20 
2017-01-03, 00:05, 30 
2017-01-02, 02:10, 40 
2017-01-03, 00:00, 50 

をこのスクリプトの結果は次のようになり日付列に基づいて3つのファイル:

ファイル名:20170101.log

date, time, measure 
2017-01-01, 00:00, 10 
2017-01-01, 01:00, 20 

ファイル名:

date, time, measure 
2017-01-02, 02:10, 40 

ファイル名を20170102.log:列ヘッダを含める必要が遊びに来るまで、このログ組換えが迅速かつ簡単です実行

date, time, measure 
2017-01-03, 00:05, 30 
2017-01-03, 00:00, 50 

20170103.log。宛先ファイルが増えるにつれて、getlineの操作にはそれぞれの呼び出しに時間がかかるようです。他の例では、test -fにファイルの存在を示すsystemの呼び出しを使用していますが、これも高価な操作であり、GNU Parallelでハングしているようです。

+0

パフォーマンスが向上しますgetline' 'なしの単純なアプローチは、おそらくそこにあります。簡単なテスト入力と希望の出力を提供すると、より多くのヘルプが得られます。 – karakfa

+0

例が追加されました。このためにAwkより優れたアプローチがありますが、現時点では既存の関連コードを再作成しないようにしています。 – MattK

答えて

0

私の問題はレコードセパレータの問題であることが判明しました。

ソースファイルはRS = "\ r \ n"(BEGINブロックで設定されています)を使用しますが、単純に出力されるため、宛先ファイルは "\ n"を区切り文字として使用します。これはgetl​​ineが行を見ないようにしていたので、宛先ファイルが増えてgetlineの時間が増えたため、ファイル全体を読み込んでいました。

マイむしろ無粋ソリューションは次のとおりです。

RS="\n" 
if (getline < (fname) < 0) { print cols > fname } 
RS="\r\n" 
1

私は、出力ファイル/パイプの配列を入力として表示し、出力ファイルの存在ではなく配列メンバシップに基づいてヘッダを追加する方法をとっています。配列メンバーシップのテストは、少なくともシェル内でtestを生成するのと比べて、すばやく行う必要があります。このような

何か:

BEGIN { 
    getline header    # this assumes we'll see a header as our 
}        # first line of input. Use whatever works. 

{ 
    outfile=$1 ".log"    # or whatever.. 
    if (!(outfile in a)) { 
    print header > outfile  # create the file with the header, 
    a[outfile]     # and record the output file. 
    } 
    print > outfile    # shard 
} 

これが存在するかどうかをテストするためにあなたのファイルシステムに触れる必要がなくなりますが、あなたが追加したいために、既存のファイルがある場合は問題となり得ます。そのために、あなたはあなたのBEGINブロック内の配列を事前格納する場合があります

BEGIN { 
    getline header 
    cmd="ls -d *.log 2>/dev/null" 
    while (cmd | getline outfile) a[outfile] 
    close(cmd) 
} 

{ 
    outfile=$1 ".log" 
    if (!(outfile in a)) { 
    print header > outfile 
    a[outfile] 
    } 
    print >> outfile 
} 

注:この亜種は、配列を事前格納するファイルのリストを取得するには(YA YA、私が知っている)lsを解析し、そのデータを追加します(>)の代わりに(>>)を使用してください。私は特殊文字を含むかもしれないログファイルに対してこれをテストしていません。一方、ファイル名は$1 ".log"なので、特殊性はすでに限定されています。

関連する問題