2

Я пытаюсь обработать довольно большой файл с разделителями табуляции (~ 30 ГБ). Я могу запустить awk, чтобы переставить столбцы, но он использует только одно ядро моего 8-ядерного компьютера. Как я могу использовать все ядра? (и значительно сократить мое время обработки) без физического разделения файла и использования большего дискового пространства?

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

Я хотел бы сделать что-то вроде этого, но не занимая больше места на диске:

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

где process_file.sh - это, по сути, оператор cut/awk выше.

Опять же, ключевая проблема здесь состоит в том, чтобы сделать этот процесс без использования еще 30 ГБ! Какие-либо предложения?

2 ответа2

1

Поскольку вы используете "split" для разделения файлов по количеству строк, а затем обрабатываете их отдельно, выводя в разные файлы (я полагаю), вы можете выполнить несколько команд "awk", каждая из которых обрабатывает только часть вашего файла на основе номера строки:

$ 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 - это внутренняя переменная "awk", которая содержит номер текущей строки. Каждая команда будет обрабатывать только строки в своем диапазоне. НО, они все также пройдут другие линии, потому что им нужно их посчитать. Я уверен, что это не поможет вам, потому что вы, скорее всего, попадете в узкое место IO. Но у вас будет несколько процессов, что позволит вам использовать несколько процессоров, если вы этого хотите. ;-)

Теперь, если у вас есть все строки одинаковой длины в байтах, вы, несомненно, сможете провести реальное распараллеливание. В этом случае вы будете использовать "dd" для извлечения точной части для каждого процесса "awk". Вы бы сделали что-то похожее на:

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

Где 30 - количество байтов в каждой строке. Если ваши строки не имеют одинаковый размер в байтах (что наиболее вероятно), но вы знаете точный байт, где начинается и заканчивается ваш блок строк, вы все равно можете сделать это с помощью dd. Изучите его параметры. Наконец, если вы не знаете, где начинаются и заканчиваются блоки, вы можете узнать их с помощью дополнительной команды awk. Но это добавляет дополнительное полное чтение в ваш файл. Если вы не будете обрабатывать файл original.tsv несколько раз по-разному, вы наверняка потратите больше времени на предварительную обработку (вычисление байтов, где начинаются и заканчиваются линейные блоки), а затем на обработку (которая, вероятно, будет иметь небольшой выигрыш, поскольку вы, безусловно, узкое место IO), чем если бы вы просто использовали решение, которое вы уже знаете.

В любом случае, теперь у вас есть информация и варианты. ;-) Удачи! (У)

0

Между прочим, команда split имеет параметр --filter=./myscript.sh который обрабатывает данные перед их записью в выходные файлы. Таким образом, у вас может быть скрипт предварительной обработки ./myscript.sh содержащий ваше преобразование, например,

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

где $FILE - выходные файлы, созданные с помощью split (например, xaa , ...). Или, чтобы избежать всех временных файлов, просто объединить в один файл,

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

Однако нет никаких оснований полагать, что это будет быстрее, чем использование split .

Учитывая, что вы выполняете обработку "больших данных" (и сколько лет прошло после того, как этот вопрос был задан изначально), возможно, также легко скопировать этот файл объемом 30 ГБ в hdfs (или, скорее, поместить и сохранить данные там). первоначально) и используйте улей apache для выбора / форматирования данных по желанию.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .