การปรับปรุงประสิทธิภาพสำหรับการ grepping ทับไฟล์ขนาดใหญ่


10

ฉันมี FILE_A ซึ่งมีมากกว่า 300,000 บรรทัดและ FILE_B ซึ่งมีมากกว่า 30 ล้านบรรทัด ฉันสร้างสคริปต์Bashที่ greps แต่ละบรรทัดใน FILE_A มากกว่าใน FILE_B และเขียนผลลัพธ์ของ grep ไปยังไฟล์ใหม่

กระบวนการทั้งหมดนี้ใช้เวลานานกว่า 5 ชั่วโมง

ฉันจะปรับปรุงประสิทธิภาพของสคริปต์ได้อย่างไร

ฉันใช้grep -F -m 1เป็นคำสั่ง grep FILE_A มีลักษณะดังนี้:

123456789 
123455321

และ FILE_B เป็นเช่นนี้:

123456789,123456789,730025400149993,
123455321,123455321,730025400126097,

ดังนั้นด้วย Bash ฉันมีwhileวนรอบที่เลือกบรรทัดถัดไปใน FILE_A และ greps มากกว่าใน FILE_B เมื่อพบรูปแบบใน FILE_B ฉันเขียนลงในไฟล์ result.txt

while read -r line; do
   grep -F -m1 $line 30MFile
done < 300KFile

คำตอบ:


17

ลองใช้grep --file==FILE_Aดู มันเกือบจะโหลดรูปแบบในหน่วยความจำอย่างแน่นอนซึ่งหมายความว่ามันจะสแกน FILE_B เพียงครั้งเดียว

grep -F -m1 --file==300KFile 30MFile

สิ่งนี้จะใช้ได้เฉพาะสมมติว่าฉันมีหน่วยความจำเพียงพอใช่ไหม
rogerio_marcio

จริง ๆ แล้วฉันไม่ได้ลองด้วยตัวเองกับไฟล์ขนาดนั้น แต่ฉันเชื่อว่ามันควรปรับปรุงความเร็วของคุณอย่างมาก หากคุณอยู่ในเครื่องที่ทันสมัยคุณไม่ควรมีปัญหาในการเก็บไฟล์ 300K ในหน่วยความจำ (หรือ 30M สำหรับเรื่องนั้น)
Gort the Robot

เมื่อฉันใช้ตัวเลือก -f (--file) มันจะสร้าง 30MFile ขึ้นใหม่ ฉันกำลังทำอะไรผิดหรือเปล่า?
rogerio_marcio

อืม ... ไฟล์ 300K อาจมีบรรทัดว่างอยู่?
Gort the Robot

ตรงจุด! นั่นมัน! มันทำงานได้อย่างสมบูรณ์มันเสร็จใน 30 วินาที! ขอบคุณ!!
rogerio_marcio

2

นี่คือคำตอบPerlสำหรับลูกหลาน ฉันทำสิ่งนี้เป็นประจำเพื่อจับคู่สาย 1M กับ 30-35M บรรทัด ใช้เวลาประมาณ 10 วินาทีจึงจะเสร็จ

ก่อนอื่นจงแฮ็ก FILE_A:

my %simple_hash;
open my $first_file, '<', 'FILE_A' or die "What have you done?! $!";
while (<$first_file>) {
  chomp;                 ## Watch out for Windows newlines
  $simple_hash{$_} = 1;  ## There may be an even faster way to define this
}
close $first_file;

แล้วถ้าไฟล์ขนาดใหญ่ของคุณจะถูกคั่นด้วยและรู้ว่าสิ่งคอลัมน์ไปหลังจากที่ตรวจสอบเพียงการดำรงอยู่ของคีย์กัญชาในขณะที่คุณวิ่งลง FILE_B ซึ่งเป็นมากมากเร็วกว่าการตรวจสอบเพื่อความเท่าเทียมกันหรือการจับคู่แสดงออกปกติ:

open my $second_file, '<', 'FILE_B' or die "Oh no, not again.. $!";
while (<$second_file>) {
  my ($col1, undef) = split ',';
  if (exists($simple_hash{$col1}) {
    print $_;
  }
}
close $second_file;

ถ้าแฟ้มเป้าหมายของคุณมีขนาดใหญ่ไม่ได้เป็นอย่างแยกสามารถแล้วสคริปต์นี้สูญเสียความคุ้มค่าเป็นอย่างมากของความเร็วมาจากการไม่ต้องไฟขึ้นแสดงออกปกติเครื่องยนต์


1

หากคุณไม่สนใจการเขียนโปรแกรมที่เกี่ยวข้องให้ลองใช้แผนผังต่อท้าย (หรือตัวแปร)

คุณสามารถประมวลผลล่วงหน้าFILE_Bโดยใช้อัลกอริทึมของ Ukkonenในเวลาเชิงเส้น จากนั้นคุณสอบถามแต่ละบรรทัดในFILE_Aเวลาเชิงเส้นในความยาวบรรทัดและรับหมายเลขบรรทัดทั้งหมดที่ตรงกัน (อาจจำเป็นต้องปรับแต่ง tree a tad) ซึ่งคุณสามารถเขียนลงในไฟล์ผลลัพธ์

ขั้นตอนการทำงานทั้งในเวลา O (n + นิวตันเมตร) ถ้า n คือความยาวของFILE_B, Nคือจำนวนของเส้นในFILE_Aและ m คือความยาวของสายที่ยาวที่สุดในFILE_A- นี้เป็นหลักรันไทม์เชิงเส้น เอาชนะเวลากำลังสองที่วิธีดั้งเดิมของคุณต้องการตามขนาด


1

ฉันพบ--mmapธงเมื่อเร็ว ๆ นี้ไม่มีโอกาสทดสอบ แต่ฉันยินดีที่จะรับฟังการค้นพบของคุณ นี่คือคำอธิบายจากหน้าคน:

--mmap If  possible, use the mmap(2) system call to read input, instead
      of the default read(2) system call.  In some situations,  --mmap
      yields  better performance.  However, --mmap can cause undefined
      behavior (including core dumps) if an input file  shrinks  while
      grep is operating, or if an I/O error occurs.

ดูนี้หรือนี้mmapสำหรับข้อมูลเพิ่มเติม


แน่นอนว่าฉันจะให้ช็อตนี้และฉันจะให้คุณรู้ว่ามันจะเป็นยังไง เป็นไปได้มากเพียงใดที่ฉันจะพบกับดัมพ์หลัก?
rogerio_marcio

@rogerio_marcio ดีเท่าที่ฉันเข้าใจคน "ถ้าไฟล์ลดลงในขณะที่ grep ทำงานหรือหากเกิดข้อผิดพลาด I / O" อาจไม่จริง แต่คุณควรจะรู้ดีกว่านี้ (ถ้าเป็นผมถือว่าไฟล์เป็น grep ในขณะที่ไม่มีใครแตะต้อง - นี้ไม่ควรเกิดขึ้น)
Ramzi Kahil

สำหรับการทดสอบ--mmapขนาดที่ไม่ทิ้งสิ่งใดฉันขอแนะนำให้ใช้ด้วย--mmapและไม่มี และจากนั้นใช้wcเพื่อดูว่าคุณมีเอาต์พุตเท่ากัน - นี่ควรเป็นการทดสอบที่มีประสิทธิภาพเนื่องจากเรารัน grep 2 ครั้งและมีเพียงค่าสถานะที่แตกต่างกัน
Ramzi Kahil

@rogerio_marcio คุณเคยลองสิ่งนี้แล้วหรือยัง? ข้อมูลเชิงลึกใด ๆ
Ramzi Kahil

-1

ทำไมคุณไม่ใส่ไฟล์นั้นลงในฐานข้อมูลฐานข้อมูลทำได้ดีมากในการผสานที่มีประสิทธิภาพการแฮชการซ้อนแบบวนซ้ำเข้าร่วมเช่นนี้ และพวกเขาใช้หน่วยความจำเสมือนได้ดี


สิ่งที่คุณทำกับคำตอบอื่น ๆ คือการสร้างวงล้อฐานข้อมูลใหม่
Andyz Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.