レコードが複数行にまたがることがある 60 GB のフラット ファイルを分割する

レコードが複数行にまたがることがある 60 GB のフラット ファイルを分割する

データを手動で入力すると、複数の改行文字を含むレコードでデータベースが汚染されます。1 つの列のみを含む 60 GB の巨大なフラット ファイルで、先頭と末尾が二重引用符で区切られた適切なレコードの場合、次のように常に 1 行に収まる必要があります。

「多数のミトコンドリアゲノム、多くの原核生物ゲノム、およびいくつかの核ゲノムの完全な配列が現在利用可能です。」

不正なレコードの場合、次のように不特定多数の複数行にまたがります。

「現在の喫煙は、高リスクと強く逆相関していた。

付随するリスク要因を調整した後のパターン。

喫煙者と現在喫煙している人は、高リスクの

パターン。 "

これらの複数行のレコードは、UNIX コマンドによる下流のファイル分割を妨げますsplitsplitは、これらの複数行を 1 つのレコードとしてインテリジェントに認識できず、1 つのレコードが別々のファイルに分割される可能性があります。 以下の Perl は、分割する前にこの巨大なファイルで不良レコードの行を最初にマージするには遅すぎます。2 時間以上待っても $count を印刷できないためです。

$file=$ARGV[0];
open(INFO, $file) or die("Could not open $file.");
open(OUT, ">out") or die("Could not open $file.");

$mergedline = "";
$count=0;
foreach $line (<INFO>)  {
    print $count++;
    if ($line =~ /^".*"\n$/) {
                print OUT $line;
                $mergedline = "";
                next;
        } elsif ($line =~ /"\n$/) {
                print OUT $mergedline;
                $mergedline = "";
                next;
        } else {
                chomp $line;
                $mergedline .= $line;
        }
}
close(INFO);

この問題を解決して、出力ファイルが「クリーン」になり、処理可能な単一行レコードのみになるようにする便利な UNIX コマンドはありますかsplit?

sedオプションのように見えますが、次の投稿のどちらもこの質問に答えていません。

https://stackoverflow.com/questions/15758814/turning-multiple-lines-into-one-line-with-comma-separated-perl-sed-awk

https://stackoverflow.com/questions/11290616/sed-conditional-merge-of-multiple-lines

http://www.unix.com/shell-programming-and-scripting/80633-sed-combining-multiple-lines-into-one.html

なぜなら、これらの投稿のパターンがあまりにも規則的で一定しているからです。

答え1

sed分割された線のみを結合するために使用する

sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output

私のシステムでは、10 MB のファイルの場合 6 秒かかります。60 GB の場合は 10 時間かかります。

bbe少し速い

bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input

それでも4秒かかります。

残念ながら、これらのスクリプト言語は、非常に大きなファイルに対して優れたパフォーマンスを発揮するツールではありません。 で小さなプログラムを書いてみてはいかがでしょうかC

答え2

使用例gawk:

awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input

これは、の後に改行 ( ) が続くinput任意のシーケンスでファイルを分割することを意味します。これにより、引用符の直後にない改行は無視され、複数行のレコードが保持されます。この例では、出力はテキスト ファイルに書き込まれますが、その部分を削除すると、代わりにレコードをパイプラインに送信できます。"\n> n".txt"

答え3

ファイルの読み込みにループを使用しているため、処理Perlが遅くなっています。ループはファイル全体を一度にメモリに読み込むため、ループを使用する必要があります。そのため、$count の印刷に非常に時間がかかります。forwhilefor

perl -ne '
   print,next if /^".*"$/m or /"$/m;
   chomp, $_ .= <>, redo unless eof;
' gene.data

関連情報