A entrada manual de dados torna o banco de dados poluído com registros contendo vários caracteres de nova linha. Para bons registros delimitados por aspas duplas no início e no final em um enorme arquivo simples de 60 GB com apenas uma única coluna, eles devem sempre abranger apenas uma linha como esta:
"Sequências completas de numerosos genomas mitocondriais, muitos procarióticos e vários genomas nucleares estão agora disponíveis."
Para registros inválidos, eles abrangem um número indefinido de múltiplas linhas como esta:
“O tabagismo atual foi forte e inversamente associado a riscos de alto risco.
padrões, após ajuste para fatores de risco concomitantes. Em relação a nunca
fumantes, os fumantes atuais eram significativamente menos propensos a ter uma doença de alto risco
padrão. "
Esses registros multilinhas proíbem a divisão de arquivos downstream pelo comando UNIX split
. split
não consegue reconhecer de forma inteligente essas múltiplas linhas como um único registro e isso pode levar à divisão de um único registro em arquivos separados. O Perl abaixo é muito lento para mesclar essas linhas para os registros inválidos primeiro para este arquivo enorme antes de dividir, já que $count não pode ser impresso após esperar por mais de 2 horas.
$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);
Qualquer comando UNIX útil para resolver este problema para que o arquivo de saída fique "limpo" com apenas registros de linha única que podem ser processados por split
?
sed
parece ser uma opção, mas nenhuma das postagens a seguir responde a esta pergunta:
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
porque os padrões dessas postagens são muito regulares e constantes.
Responder1
Usando sed
para unir apenas as linhas divididas
sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output
leva 6 segundos para um arquivo de 10 MB no meu sistema. Isso seria 10 horas para 60 GB.
bbe
é um pouco mais rápido
bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input
mas ainda leva 4 segundos.
Receio que essas linguagens de script não sejam a ferramenta para um bom desempenho em arquivos extremamente grandes. Que tal escrever um pequeno programa em C
?
Responder2
exemplo usando gawk
:
awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input
Isso diz dividir o arquivo input
em qualquer sequência "
seguida por uma nova linha ( \n
). Isso ignorará as novas linhas que não seguem imediatamente as aspas, preservando os registros multilinhas. Neste exemplo, a saída é gravada em um arquivo de texto, mas se você remover a > n".txt"
parte, poderá enviar registros para um pipeline.
Responder3
Você Perl
está lento por causa do for
loop que está sendo usado para ler o arquivo. Você realmente deveria estar usando o while
loop, já que o for
loop carrega o arquivo inteiro na memória de uma só vez. É por isso que está demorando uma eternidade para imprimir $count.
perl -ne '
print,next if /^".*"$/m or /"$/m;
chomp, $_ .= <>, redo unless eof;
' gene.data