การใช้ GNU Parallel พร้อม Split


9

ฉันกำลังโหลดไฟล์ขนาดมหึมาไปยังฐานข้อมูล postgresql การทำเช่นนี้ผมใช้งานครั้งแรกsplitในแฟ้มที่จะได้รับไฟล์ขนาดเล็ก (30GB) และแล้วผมโหลดแต่ละไฟล์ขนาดเล็กเพื่อใช้ฐานข้อมูลและGNU Parallelpsql copy

ปัญหาคือว่าจะใช้เวลาประมาณ 7 ชั่วโมงในการแบ่งไฟล์แล้วจึงเริ่มโหลดไฟล์ต่อหนึ่งคอร์ สิ่งที่ฉันต้องการคือวิธีที่จะบอกsplitให้พิมพ์ชื่อไฟล์ไปยังเอาต์พุต std ทุกครั้งที่มันเสร็จสิ้นการเขียนไฟล์เพื่อที่ฉันจะได้ไพพ์ไปParallelและมันก็เริ่มโหลดไฟล์ในเวลาที่splitเขียนมันเสร็จ บางสิ่งเช่นนี้

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

ฉันอ่านsplitman pages แล้วและฉันไม่พบอะไรเลย มีวิธีการทำเช่นนี้กับsplitหรือเครื่องมืออื่น ๆ ?

คำตอบ:


13

ใช้ - ท่อ:

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

มันต้องการ. /carga_postgres.sh เพื่ออ่านจาก stdin ไม่ใช่จากไฟล์และช้าสำหรับ GNU Parallel version <20130222

หากคุณไม่ต้องการเส้น 50,00000000 เส้น - บล็อกนั้นเร็วกว่า:

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 หรือ - แมวสามารถช่วยคุณได้
Ole Tange

2

ทำไมไม่ใช้ --pipe AND --pipepart กับ GNU Parallel สิ่งนี้จะกำจัด cat พิเศษและเริ่มอ่านโดยตรงจากไฟล์บนดิสก์:

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.