Execute comandos awk paralelos em um arquivo grande, sem espaço de arquivo extra

2

Estou tentando processar um arquivo separado por tabulação bastante grande (~ 30 GB). Eu posso rodar o awk para reorganizar as colunas, mas ele usa apenas um único núcleo da minha máquina de 8 núcleos. Como posso usar todos os núcleos? (e reduzir drasticamente o tempo de processamento) sem dividir fisicamente o arquivo e usar mais espaço em disco?

cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged.tsv

Eu gostaria de fazer algo assim, mas sem usar mais espaço em disco:

split -l 50000 original.tsv sp
for i in $(dir sp*); do ./process_file.sh $i & done;

em que process_file.sh é essencialmente a instrução cut / awk acima.

Novamente, o principal problema aqui é fazer esse processo sem usar outros 30GB! Alguma sugestão?

    
por MadmenDiver 18.07.2012 / 08:23

2 respostas

1

Como você está usando o "split" para separar seus arquivos por número de linhas, então processe-os separadamente para arquivos diferentes (eu acho), você pode fazer vários comandos "awk", cada um processando apenas parte do arquivo baseado no arquivo. número da linha:

$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; (NR < 50000){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 50000) && (NR < 100000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 100000) && (NR < 150000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

NR é uma variável interna para "awk" que contém o número da linha atual. Cada comando processaria apenas as linhas em seu intervalo. MAS , eles também passam pelas outras linhas, porque precisam contá-las. Tenho certeza que não vai ajudar você, porque você provavelmente vai cair no gargalo do IO. Mas você terá vários processos, permitindo que você use várias CPUs, se é isso que você quer. ; -)

Agora, SE você tem todas as linhas com o mesmo comprimento em bytes, você certamente pode fazer uma paralelização real. Nesse caso, você usará "dd" para extrair a parte exata de cada processo "awk". Você faria algo semelhante a:

dd if=original.tsv bs=30 count=50000 skip=0 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv

dd if=original.tsv bs=30 count=50000 skip=50000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv

dd if=original.tsv bs=30 count=50000 skip=100000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

Onde 30 é o número de bytes em cada linha. Se suas linhas não são todas do mesmo tamanho em bytes (o que é mais provável) mas você sabe o byte exato onde seu bloco de linhas começa e termina, você ainda pode fazê-lo usando o dd. Estude seus parâmetros. Finalmente, se você não sabe onde os blocos começam e terminam, você pode encontrá-los com um comando extra awk. Mas isso adiciona uma leitura extra completa no seu arquivo. A menos que você processe seu arquivo original.tsv várias vezes de maneiras diferentes, você certamente gastará mais tempo pré-processando (calculando os bytes onde os blocos de linha começam e terminam) e depois processando (o que provavelmente terá um pequeno ganho porque você certamente ter um gargalo de IO) do que se você simplesmente usasse a solução que já conhece.

De qualquer forma, agora você tem informações e opções. ;-) Boa sorte! (y)

    
por 23.08.2012 / 03:36
0

Fwiw, o comando split tem uma opção --filter=./myscript.sh que processa os dados antes de serem gravados no (s) arquivo (s) de saída. Você pode ter um script de pré-processamento chamado ./myscript.sh contendo sua transformação, por exemplo,

cut ... | awk '...' > $FILE

em que $FILE são os arquivos de saída gerados por split (por exemplo, xaa , ...). Ou, para evitar todos os arquivos temporários, basta concatenar para um único arquivo,

cut ... | awk '...' >> abridged.tsv

Não há razão para acreditar que isso seria mais rápido do que não usar split , no entanto.

Considerando que você está processando "big data" (e quantos anos depois que essa pergunta foi originalmente feita), provavelmente também é tão fácil copiar esse arquivo de 30GB para hdfs (ou melhor, colocar & mantenha os dados lá originalmente) e use a seção apache para selecionar / formatar os dados conforme desejado.

    
por 30.12.2017 / 15:03