Split ile GNU Paralel Kullanma


9

Postgresql veritabanına oldukça devasa bir dosya yüklüyorum. Bu ilk kullanımını yapmak için splitdaha küçük dosyalar (30Gb her) almak için dosyada ve sonra kullanarak veritabanına her küçük bir dosya yüklemek GNU Parallelve psql copy.

Sorun, dosyayı bölmenin yaklaşık 7 saat sürmesi ve çekirdek başına bir dosya yüklemeye başlamasıdır. İhtiyacım olan şey, bir splitdosya yazmayı bitirdiğinde her dosyaya std çıktısına dosya adını yazdırmayı söylemenin bir yoludur, böylece Parallelonu borulandırabilir ve dosyaları splityazmayı bitirdikten sonra yüklemeye başlar . Bunun gibi bir şey:

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

splitAdam sayfalarını okudum ve hiçbir şey bulamıyorum. Bunu splitveya başka bir araçla yapmanın bir yolu var mı ?

Yanıtlar:


13

--Pipe kullanın:

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

./Carga_postgres.sh dosyasının bir dosyadan değil stdin'den okunması gerekir ve GNU Paralel sürümü <20130222 için yavaştır.

Tam olarak 50000000 hatta ihtiyacınız yoksa --block daha hızlıdır:

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

Bu, \ n üzerinde yaklaşık 500 MB'lık bölünmüş parçalar geçirir.

./Carga_postgres.sh içeriğinin ne olduğunu bilmiyorum, ama tahminim kullanıcı adı şifresi ile psql içeriyor. Bu durumda GNU SQL'i (GNU Parallel'ın bir parçası olan) kullanmak isteyebilirsiniz:

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

En büyük yararı, geçici dosyaları kaydetmeniz gerekmemesi, ancak hepsini bellekte / borularda tutabilmenizdir.

./Carga_postgres.sh stdin'den okuyamıyorsa, ancak bir dosyadan okuması gerekiyorsa, dosyayı bir dosyaya kaydedebilirsiniz:

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

Büyük işler genellikle yarı yolda kalır. GNU Parallel, başarısız işleri yeniden çalıştırarak size yardımcı olabilir:

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

Bu başarısız olursa, yukarıdakileri yeniden çalıştırabilirsiniz. Başarılı bir şekilde işlenen blokları atlayacaktır.


1
GNU Parallel> 20140422 yazılımının yeni bir sürümüne sahipseniz @ RobertB'nin yanıtını --pipepart ile kullanın. Bu doğrudan işe yaramazsa --fifo veya --cat'in size yardımcı olup olamayacağını görün.
Ole Tange

2

Neden GNU Paralel ile --pipe AND --pipepart kullanılmıyor? Bu, ekstra kediyi ortadan kaldırır ve diskteki dosyadan doğrudan okumaları başlatır:

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

1

Burada cevaplar karmaşık yol olarak bulundu, bu yüzden Stack Overflow sordum ve bu cevabı aldım :

Eğer kullanırsanız GNU split, sen ile yapabilirsiniz --filterseçeneği

'--filter = command'
Bu seçenekle, her çıktı dosyasına yazmak yerine, her çıktı dosyası için belirtilen kabuk komutuna bir kanaldan yazın. komut, komutun her çağrılması için farklı bir çıktı dosyası adına ayarlanmış $ FILE ortam değişkenini kullanmalıdır.

Bir dosya oluşturan bir kabuk betiği oluşturabilir ve arka planın sonunda carga_postgres.sh dosyasını başlatabilirsiniz.

#! /bin/sh

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

ve bu komut dosyasını filtre olarak kullanın

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

0

splitDosya adlarını yazdırmanın bir alternatifi , dosyaların ne zaman hazır olduğunu algılamaktır. Linux'ta inotify özelliğini ve özellikle inotifywaityardımcı programı kullanabilirsiniz.

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

inotifywaitManuel olarak öldürmeniz gerekecek . Potansiyel bir yarış durumu olduğu için otomatik olarak öldürmek biraz zordur: splitbitirir bitmez öldürürseniz , henüz bildirmediği olaylar almış olabilir. Tüm olayların raporlandığından emin olmak için eşleşen dosyaları sayın.

{
  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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.