Como classificar arquivos grandes?

35

Eu tenho um PC com CPU Intel (R) Pentium (R) G640 a 2,80 GHz e 8 GB de RAM. Estou executando o Scientific Linux 6.5 nele com o sistema de arquivos EXT3.

Nessa configuração, qual é a maneira mais rápida de fazer um sort -uarquivo de 200 gigabytes?

Devo dividir o arquivo em arquivos menores (menores que 8 GB) sort -u, juntá-los e dividi-los novamente em um tamanho diferente, sort -unovamente etc.? Ou existem scripts de classificação, programas que podem lidar com arquivos tão grandes com minha quantidade limitada de RAM?

evacristina
fonte
6
Por favor edite sua pergunta e explicar o que acontece quando você tenta o comando que você postou. Você fica sem espaço em disco? O comando deve funcionar desde que você tenha espaço livre suficiente no seu /tmp.
terdon
11
A resposta escolhida basicamente diz o que @terdon está dizendo, mas também confira esta - stackoverflow.com/a/13025731/2801913 . parallelAcho que você precisará do GNU para isso, em vez do moreutils parallelinstalado por padrão em alguns sistemas.
Graeme
11
Você pode carregar o arquivo no Amazon S3 e, em seguida, criar um trabalho Elastic Map Reduce com algumas centenas de nós para classificá-lo!
Alan Shutko
2
sort(1)poderia ficar sem espaço /tmp; Se assim for, você pode designar uma outra área para arquivos temporários com a variável de ambiente TMPDIR, ou a bandeira-T=<tmpdir>
vonbrand

Respostas:

46

O GNU sort(que é o padrão na maioria dos sistemas Linux), tem uma --parallelopção. Em http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html :

'--parallel = n'

Defina o número de classificações executadas em paralelo para n. Por padrão, n é definido como o número de processadores disponíveis, mas limitado a 8, pois há ganhos de desempenho decrescentes depois disso. Observe também que o uso de n threads aumenta o uso de memória por um fator de log n. Veja também invocação nproc.

Como sua CPU possui 2 núcleos, você pode:

sort --parallel=2 -uo list-sorted.txt list.txt

É melhor especificar o número real de núcleos, pois pode parecer haver mais devido ao fato de o processador ter hiperencadeamento .

Você também pode experimentar niceinfluenciar a prioridade de planejamento do processador e ioniceinfluenciar o planejamento de E / S. Você pode aumentar a prioridade em relação a outros processos como este, acho que isso não lhe dará grandes economias, pois geralmente são melhores para garantir que um processo em segundo plano não use muitos recursos. No entanto, você pode combiná-los com algo como:

nice -n -20 ionice -c2 -n7 sort --parallel=2 -uo list-sorted.txt list.txt

Observe também que, como Gilles comentou, o uso de um único comando de classificação GNU será mais rápido do que qualquer outro método de quebrar a classificação, pois o algoritmo já está otimizado para lidar com arquivos grandes. Qualquer outra coisa provavelmente apenas atrasará as coisas.

Graeme
fonte
10
E você deve observar que ligar sortdiretamente é melhor do que qualquer outra coisa que você possa fazer. A classificação GNU foi projetada para lidar bem com arquivos muito maiores que a RAM.
Gilles 'SO- stop be evil'
A opção de classificação --parallel não funciona nos meus servidores RH6.5. Classificação - versão pensa que sai do coreutils 8.4. Qual versão eu preciso para a versão paralela?
Markus_b
3
Consulte também superuser.com/questions/938558/sort-parallel-isnt-parallelizing - talvez seja necessário especificar algo como -S512M se você notar que não é realmente paralelo.
Unhammer #
46

Usar o sortcomando provavelmente será a opção mais rápida.

Mas você provavelmente desejará corrigir o código do idioma para C.

sort -unão relata linhas exclusivas, mas uma de cada conjunto de linhas que são iguais. No código C, duas linhas diferentes não necessariamente são iguais, mas esse não é o caso na maioria dos locais baseados em UTF-8 nos sistemas GNU.

Além disso, o uso da localidade C evita a sobrecarga de analisar o UTF-8 e o processamento de ordens de classificação complexas, melhorando drasticamente o desempenho.

Tão:

LC_ALL=C sort -u file

Você também pode melhorar o desempenho usando uma unidade mais rápida (ou diferente da onde estão os arquivos de entrada e / ou saída) para os arquivos temporários (usando -Tou $TMPDIRvariável de ambiente) ou mexendo na -Sopção suportada por algumas sortimplementações) .

Para algum tipo de entrada ou armazenamento lento, o uso da --compress-programopção GNU sort(por exemplo, com lzop) pode melhorar o desempenho, além do uso do armazenamento.


Agora, apenas uma observação para aqueles que objetam (com certa razão) que não será a ordem correta :

Concordo que, como humano, gostaria de ver Stéphane entre Stefan e Stephanie , mas:

  • Um computador deseja que Stéphane classifique depois de é(pelo menos quando expresso como U + 00E9) como um caractere ou os bytes de sua codificação UTF-8 são classificados depois (em termos de valor de ponto de código ou byte). Essa é uma ordem de classificação que é muito simples de implementar, é uma ordem total estrita e não tem surpresa.
  • A ordem de classificação do seu código de idioma provavelmente não será satisfatória em muitos casos, mesmo para um ser humano. Por exemplo, no meu sistema com o código de idioma padrão en_GB.utf8:

    • Stéphane e Stéphane (um com U + 00E9 e outro com eU + 0301) não são da mesma forma:

      $ printf '%b\n' 'Ste\u0301phane' 'St\u00e9phane' | sort -u
      Stéphane
      Stéphane
      
    • mas ③, ①, sort são todos iguais (obviamente um erro nessas definições de localidade):

      $ printf '%s\n' ③ ① ② | sort -u
      ③
      

      Aqui é ③, mas poderia muito bem ter sido ① ou ②

Então, na IMO, é provável que você sempre deseje sort -ucom LC_ALL = C, se quiser linhas únicas. E se você deseja que a lista resultante seja classificada na ordem de classificação do usuário, canalize-a sortnovamente:

LC_ALL=C sort -u | sort

LC_ALL=C sort | LC_ALL=C uniq -c | sort -k2
Stéphane Chazelas
fonte
8
+1 para definição de região: pode ter um enorme efeito sobre o desempenho
Adrian Pronk
11
Sim. classificando arquivo com 250000 linhas, o LC_ALL acelera as coisas 8 vezes.
Jan Vlcinsky
-1

Aqui está um script bash pronto para usar para classificar dados da escala de TB em uma máquina comum com dois GB de RAM: http://sgolconda.blogspot.com/2015/11/sort-very-large-dataset.html Ele verifica o número de núcleos de sua máquina e usa todos os núcleos. Pode classificar arquivos numéricos ou de sequência. Pode ser usado para encontrar registros exclusivos nos dados da escala de TB.

user213743
fonte
Esta não é uma boa sugestão. O script é imensamente inchado e divide o arquivo de entrada para classificar as partes que a resposta aceita aponta que não são necessárias na classificação do GNU.
Thorbjørn Ravn Andersen