かなり大きなファイルをpostgresqlデータベースにロードしています。これを行うには、最初にsplit
ファイルを使用して小さなファイル(それぞれ30 Gb)を取得し、各GNU Parallel
小さなファイルをデータベースにロードするために使用しましたpsql copy
。
問題は、ファイルを分割した後、コアごとに1つのファイルをロードし始めるのに約7時間かかります。私にとって必要なのは、ファイルの書き込みが終わるたびにファイル名をstd出力に印刷して、書き込みが終わったらパイプしてsplit
ファイルParallel
のロードを開始できるようにする方法です。split
このような:
split -l 50000000 2011.psv carga/2011_ | parallel ./carga_postgres.sh {}
split
マニュアルページを読みましたが、何も見つかりません。split
他のツールや他のツールを使用してこれを行う方法はありますか?
答え1
--pipelineを使用してください:
cat 2011.psv | parallel --pipe -l 50000000 ./carga_postgres.sh
ファイルではなく標準入力から読み取るには ./carga_postgres.sh が必要で、GNU パラレルバージョン < 20130222 では速度が遅い
正確に50000000行を必要としない場合は、--blockが高速です。
cat 2011.psv | parallel --pipe --block 500M ./carga_postgres.sh
これにより、約 500 MB の分割チャンクが \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 が標準入力から読み取れないがファイルから読み取る必要がある場合は、ファイルに保存できます。
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 {#}"
失敗した場合は、上記のコマンドを再実行できます。正常に処理されたブロックはスキップされます。
答え2
GNU Parallelで--pipeと--pipepartを使用しないのはなぜですか?これにより、追加のcatが削除され、ディスクから直接ファイルを読み始めます。
parallel --pipe --pipepart -a 2011.psv --block 500M ./carga_postgres.sh
答え3
ここに投稿された回答が非常に複雑であることがわかったので、Stack Overflowに連絡して回答を受けました。これ答え:
使用する場合GNU split
、--filter
オプションを使用してこれを行うことができます。
'--filter = command'
このオプションを使用すると、単に各出力ファイルに書き込むのではなく、指定されたシェルコマンドがパイプを介して各出力ファイルに書き込まれます。コマンドは、コマンドを呼び出すたびに異なる出力ファイル名に設定されている$ FILE環境変数を使用する必要があります。
ファイルを生成し、バックグラウンドでCargo_postgres.shを起動するシェルスクリプトを生成できます。
#! /bin/sh
cat >$FILE
./carga_postgres.sh $FILE &
このスクリプトをフィルタとして使用します。
split -l 50000000 --filter=./filter.sh 2011.psv
答え4
ファイル名を印刷するもう1つの方法は、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)