2016-09-10 3 views
0

私は値と頻度を含むファイルを持っています。私はawk {a [$ 1] + = $ 2} END というコマンドを使用して、同じ値の列の頻度を追加しました。しかし、ファイルには3GBのデータが含まれており、私はメモリ効率的なソリューションが必要です。だから私はあなたの後の最初のプロセスデータをソートファイルawkのメモリ効率的なソリューションに共通の値を追加

+2

あなたは短いサンプルソートされた入力ファイルとそれを試したawkコマンドを投稿することができます...また、期待されるサンプル出力... – Sundeep

+0

私はファイルを分割することも助けになると思います.. – Sundeep

+0

あなたの入力ファイルは3gは無関係です。重要なのはあなたが持っているユニークな「価値」の数です。だからあなたはどれくらいの人がいられるのですか?答えが5の場合、必要な解は、答えが3gの場合と大きく異なることになります。既に要求されているように、簡潔でテスト可能なサンプル入力と予想される出力を投稿することで、お手伝いします。私はあなたが最初にファイルをソートしているのを見ています。ソートはファイル全体をメモリに読み込んで仕事をするので、そのメモリはいかに効率的でしたか?たぶんあなたは持っていない問題を解決しようとしています。 –

答えて

1

どの程度であれば、最初のファイルをソートし、それらが同じである場合は、連続する列を追加しようとしたが、私はそうするために失敗しています:

$ cat > assumed_data.txt 
VALUE1 1 
VALUE2 2 
VALUE1 3 
VALUE2 4 
$ sort assumed_data.txt|awk 'NR>1 && prev != $1 {print prev, sum; sum=0} {sum+=$2; prev=$1} END {print prev, sum}' 
VALUE1 4 
VALUE2 6 
+0

合理的なアプローチですが、もしOPが 'awk'がファイル全体を読むのに十分なメモリを持っていなければ、' sort 'がファイル全体を読み込むのに十分なメモリがほとんどありません。 –

0

...またはカウントし、それらをプリントアウトバッチで、例のプロセス1000行のために、別のファイルにそれらをプリントアウトし、その後、次の1000行と同じファイルに追加:

$ cat divisum.awk 
NR % 1000 ==0 { 
    for(i in sum) 
     print i, sum[i] 
    delete sum 
} 
{ 
    sum[$1]+=$2 
} 
END { 
    for(i in sum) 
     print i, sum[i] 
} 
$ awk -f divisum.awk assumed_data.txt > summedsome.txt 

、その後:

$ awk -f divisum.awk summedsome.txt > summedsomore.txt 

...など。あなたのデータがすべて1000であるかどうかわからない場合は、適切な数の行であるかもしれません。あなたのファイルが1000の異なる値を均等に分散させている場合、一度に1000行はあなたの問題を解決しません。

+0

出力ファイルにすべてのユニークな値があるまでループするためにはいくつかの外部ロジックを追加する必要があります。これは、見た目を追跡するために値の配列のようなものを必要とし、新しい値がこれは、OPが解決しなければならない問題であるユニークな値の配列を持つことに戻り、ユニークな値の配列に十分なメモリがないことを意味します。 –

0

あなたは本当にあなたがあなたのファイルにsortを実行する可能性があるので、あなたはそれに対処するために、このような何かを必要とするだろうどの私はあなたが確信していない、メモリの問題を持っている場合:

awk ' 
    !full { 
     if (($1 > prevMax) || (NR == FNR)) { 
      sum[$1] += $2 
      if (length(sum) == 1000000) { 
       full = 1 
       for (i in sum) { 
        min = ($1<min ? $1 : min) 
        max = ($1>max ? $1 : max) 
       } 
      } 
     } 
     next 
    } 
    ($1 >= min) && ($1 =< max) { 
     sum[$1] += $2 
    } 
    ENDFILE { 
     if (length(sum) > 0) { 
      for (i in sum) { 
       print i, sum[i] 
      } 
      ARGV[ARGC] = FILENAME 
      ARGC++ 
      delete sum 
      full = 0 
      prevMax = max 
     } 
    } 
' file 

をチェック数学/論理を使用していますが、一度に1000000までのユニークな値を数え、ユニークな値がなくなるまで入力ファイルをARGVリストに追加しておくことをお勧めします。マッサージ1000000に合わせて。

上記では、ENDFILEにGNU awkを使用していますが、ファイル内の行数を使用するか、FNR == 1を使用して終了記号などを使用する必要があります。

0

あなたは、多くの場合、ディスクのRAMを交換し、その値によって、ファイルにそれを分割ファイルを介して1つのパスを作ることができます - ので、すべてのVALUE1周波数がファイルf.VALUE1に移動し、すべてのVALUE2周波数がファイルf.VALUE2に行きます。

awk '{print $2 > "f." $1}' yourFile 

次に、あなたは自明f.*のそれぞれの数字を合計する必要があります。この解決策は、一度に1つの行だけをメモリに保持します:-)

0

これに近づく別の方法は、GNUパラレルです。ファイルを任意のサイズのブロックにまとめることができ、それらを並列に処理することができます。それはフルラインでのみ分割されます - 私が提案していない他のものを行わない限り、ライン内で分割のリスクはありません。私は10メガバイトの塊にGNUパラレルチャンクファイルを持っているようにそれらを渡すことができ

{a[$1]+=$2} 
END{for(i in a)print i,a[i]} 

とあなたのファイルを想定したがdataと呼ばれ、:

だから、次のように私はscript.awkであなたのawkスクリプトを使用すると仮定するとあなたのCPUはコアを持っているとして、並列に多くのawk S:

parallel -a data --pipepart --block 10m awk -f ./script.awk 

今では、限り、いくつかのREPEがあるので、あなたのデータを削減します任意の10MBチャンク内のated値。明らかにチャンクを大きくすることができ、参照のローカリティ性が向上するため、チャージサイズを大きくすることで、チャンクサイズを変更することでメモリが足りないという理論をテストすることもできます。また、ファイルサイズがメモリよりも小さくなるまで上記を繰り返して適用することができます。つまり、メモリ内のすべてのファイルを1つにまとめることができます。私は意味:

parallel -a data --pipepart --block 10m awk -f ./script.awk > part1 
parallel -a part1 --pipepart --block 10m awk -f ./script.awk > part2 

エドが言うように、質問はあなたが持っているどのように多くのユニーク値ではなく、あなたが持っているどのように多くの値です。ユニークな値が少ないほど、ファイル内でより近い値になるほど、この方法はより速く収束します。

関連する問題