スプリットでGNU Parallelを使用する


9

かなり巨大なファイルをpostgresqlデータベースにロードしています。このI最初の使用を行うには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

ファイルからではなくstdinから読み取るには./carga_postgres.shが必要であり、GNU Parallelバージョン<20130222の場合は低速です。

正確に50000000行が必要ない場合は、-blockの方が高速です。

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

これにより、約500MBに分割されたチャンクが\ 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が役立つかどうかを確認してください。
Ole

2

GNU Parallelで--pipe AND --pipepartを使用しないのはなぜですか?これにより、余分な猫が排除され、ディスク上のファイルから直接読み取りが開始されます。

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

1

私はここに投稿された回答が複雑になる方法であることを発見したので、Stack Overflowに質問し、この回答を得ました。

を使用する場合GNU splitは、--filterオプションでこれを行うことができます

'--filter = command'
このオプションを使用すると、単に各出力ファイルに書き込むのではなく、パイプを介して各出力ファイルの指定されたシェルコマンドに書き込みます。コマンドは$ FILE環境変数を使用する必要があります。この環境変数は、コマンドの呼び出しごとに異なる出力ファイル名に設定されます。

ファイルを作成し、最後にバックグラウンドでcarga_postgres.shを開始するシェルスクリプトを作成できます。

#! /bin/sh

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

そのスクリプトをフィルターとして使用します

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

0

splitファイル名を印刷する代わりに、ファイルの準備ができたことを検出することもできます。Linuxでは、inotify機能、特に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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.