Використання GNU Паралельно зі Спліт


9

Я завантажую досить гігантський файл у базу даних postgresql. Для цього я спочатку використовую splitу файлі для отримання менших файлів (30Gb кожен), а потім завантажую кожен менший файл у базу даних за допомогою GNU Parallelі psql copy.

Проблема полягає в тому, що потрібно розділити файл близько 7 годин, а потім він починає завантажувати файл на ядро. Що мені потрібно, це спосіб сказати splitнадрукувати ім'я файлу для виведення std кожного разу, коли він закінчує запис файлу, щоб я міг передати Parallelйого, і він починає завантажувати файли в момент splitзакінчення його написання. Щось на зразок цього:

split -l 50000000 2011.psv carga/2011_ | parallel ./carga_postgres.sh {}

Я прочитав splitсторінки чоловіків і нічого не можу знайти. Чи є спосіб це зробити за допомогою splitбудь-якого іншого інструменту?

Відповіді:


13

Використовуйте --pipe:

cat 2011.psv | parallel --pipe -l 50000000 ./carga_postgres.sh

Він вимагає ./carga_postgres.sh читати зі stdin, а не з файлу, і для GNU Parallel версія <20130222 повільна.

Якщо вам не потрібно точно 50000000 рядків, --блок швидше:

cat 2011.psv | parallel --pipe --block 500M ./carga_postgres.sh

Це передасть шматки розміром близько 500 Мб на \ n.

Я не знаю, що містить ./carga_postgres.sh, але я гадаю, що він містить psql з паролем ім'я користувача. У цьому випадку ви можете використовувати GNU SQL (який є частиною GNU Parallel):

cat 2011.psv | parallel --pipe --block 500M sql pg://user:pass@host/db

Основна перевага полягає в тому, що вам не потрібно зберігати тимчасові файли, але ви можете зберігати всі в пам'яті / трубах.

Якщо ./carga_postgres.sh не може читати з stdin, але повинен читати з файлу, ви можете зберегти його у файл:

cat 2011.psv | parallel --pipe --block 500M "cat > {#}; ./carga_postgres.sh {#}"

Великі робочі місця часто провалюються на півдорозі. GNU Parallel може допомогти вам, повторно запустивши невдалі завдання:

cat 2011.psv | parallel --pipe --block 500M --joblog my_log --resume-failed "cat > {#}; ./carga_postgres.sh {#}"

Якщо це не вдалося, ви можете повторно запустити вище. Він пропустить блоки, які вже успішно обробляються.


1
Якщо у вас є нова версія GNU Parallel> 20140422, скористайтеся відповіддю @ RobertB з --pipepart. Якщо це не працює безпосередньо, перевірте, чи --fifo або --cat можуть вам допомогти.
Оле Танге

2

Чому б не використовувати --pipe AND --pipepart з GNU Parallel? Це виключає зайву кішку і починає пряме зчитування з файлу на диску:

parallel --pipe --pipepart -a 2011.psv --block 500M ./carga_postgres.sh

1

Я знайшов відповіді, розміщені тут, як складні, тому запитав про переповнення стека, і я отримав цю відповідь:

Якщо ви використовуєте GNU split, ви можете зробити це за допомогою --filterопції

'--filter = команда'
За допомогою цього параметра, а не просто писати до кожного вихідного файлу, записуйте через трубу до вказаної команди оболонки для кожного вихідного файлу. команда повинна використовувати змінну середовища $ FILE, яка встановлюється для іншого виводу вихідного файлу для кожного виклику команди.

Ви можете створити скрипт оболонки, який створює файл і запустити carga_postgres.sh наприкінці на задньому плані

#! /bin/sh

cat >$FILE
./carga_postgres.sh $FILE &

і використовувати цей сценарій як фільтр

split -l 50000000 --filter=./filter.sh 2011.psv

0

Альтернативою для splitдруку імен файлів є виявлення, коли файли готові. В Linux ви можете скористатися засобом ініціації та, зокрема, inotifywaitутилітою.

inotifywait -m -q -e close_write --format %f carga | parallel ./carga_postgres.sh &
split -l 50000000 2011.psv carga/2011_

Вам потрібно буде вбити inotifywaitвручну. Вбити його автоматично трохи важко, тому що існує потенційна умова гонки: якщо ви вб'єте його, як тільки splitзакінчиться, він, можливо, отримав події, про які він ще не повідомив. Щоб переконатися, що всі події повідомляються, порахуйте відповідні файли.

{
  sh -c 'echo $PPID' >inotifywait.pid
  exec inotifywait -m -q -e close_write --format %f carga
} | tee last.file \
  | parallel ./carga_postgres.sh &
split -l 50000000 2011.psv carga/2011_
(
  set carga/2011_??; eval "last_file=\${$#}"
  while ! grep -qxF "$last_file" last.file; do sleep 1; done
)
kill $(cat inotifywait.pid)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.