เลือกออปชัน grep ให้เหมาะ ลดเวลาค้นหาได้มาก

ช่วงนี้รับงาน เพื่อเขียนโปรแกรมดึงข้อมูลจาก text file ทำเป็นรายงานสรุป โดยข้อมูลที่ได้มา มีจำนวนบรรทัดมากมายมหาศาล รวมๆ แล้วเป็น หมื่นล้านบรรทัด

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

ข้อมูลที่อยู่ในไฟล์ แยกเป็นบรรทัด เหมือนกับ CSV ไฟล์ งานแรกที่ต้องทำคือ เขียนโปรแกรมเพื่อดึงข้อมูลเฉพาะบรรทัดที่มีคำที่ต้องการเท่านั้น

หมายเหตุ

  • เพื่อไม่ให้เวลาเพี้ยนไปเนื่องจากการทำ cached file บน Linux  ทุกครั้งก่อนรันคำสั่ง จะรัน cat เพื่อพยายามให้ไฟล์อยู่ใน cached เหมือนกันทุกครั้ง
  • เนื่องจากข้อมูลมีปริมาณมาก การแสดงผลออกหน้าจอจะทำให้เวลาที่ได้เพี้ยนไป ดังนั้น ในการรันทุกคำสั่ง output ที่ได้ จะถูกส่งไปยัง /dev/null
  • ใช้คำสั่ง time เพื่อจับเวลาในการรันคำสั่ง

ตัวอย่างการรันคำสั่ง cat ทุกครั้ง เพื่อพยายามโหลดไฟล์ข้อมูลเข้า cached

[user1@devel tmp]$ time cat test-data.txt > /dev/null
real    0m0.519s
user    0m0.247s
sys     0m0.272s

ใช้คำสั่ง wc -l เพื่อนับจำนวนบรรทัดของไฟล์ ไฟล์ข้อมูลที่ใช้ทดสอบ มีจำนวนบรรทัด 5,825,368 บรรทัด

[user1@devel tmp]$ wc -l cat test-data.txt
5813492

ต้องการดึงข้อมูลจากบรรทัดที่มีคำว่า “jan” หรือมีคำว่า “feb”

grep -E หรือ egrep (extended-regexp)

เราสามารถใช้คำสั่ง grep ตามด้วยออปชั่น -E หรือคำสั่ง egrep เพื่อเลือกเฉพาะบรรทัดที่มีคำที่ต้องการแบบมีเงื่อนไข extended regular expression

[user1@devel tmp]$ time grep -E "(jan|feb)" test-data.txt  > /dev/null
real    0m22.070s
user    0m19.298s
sys     0m3.038s

หรือใช้คำสั่ง egrep ก็ให้ผลเหมือนกัน

[user1@devel tmp]$ time egrep "(jan|feb)" test-data.txt > /dev/null
real    0m21.530s
user    0m19.133s
sys     0m2.831s

ใช้เวลาไปประมาณ 20 กว่าวินาที ก็ได้ผลลัพธ์ที่ต้องการ

แต่เมื่อคิดคำนวนคร่าวๆ   5 ล้านกว่าบรรทัด ใช้เวลา 20 วินาที แล้ว 10,000 ล้านบรรทัดล่ะ นี่ยังไม่รวมกระบวนการอื่นๆ ที่ต้องทำต่อไปอีกนะ –”

grep แยกทีละคำ

เมื่อคิดเรื่องเวลาแล้ว เลยหาวิธีใหม่ คือทดลอง grep แยกทีละคำ

หาเฉพาะที่มีคำว่า “jan” เวลาที่ใช้แค่ 1 วินาทีกว่าๆ

[user1@devel tmp]$ time grep "jan" test-data.txt > /dev/null
real    0m1.472s
user    0m1.522s
sys     0m0.375s

หาเฉพาะที่มีคำว่า “feb” เวลาที่ใช้ไม่ถึงวินาที

[user1@devel tmp]$ time grep "feb" test-data.txt > /dev/null
real    0m0.464s
user    0m0.381s
sys     0m0.108s

รวมๆ แล้ว เร็วกว่ามาก grep แยกทีละคำก็น่าจะดี แต่คงยุ่งยากในการเขียนโปรแกรมพอสมควร ยิ่งถ้ามีคำที่ต้องการค้นหาเพิ่มมาอีก

*** grep -P (perl-regexp) ***

อ่าน man page ของ grep พบอีกออปชั่น  -P เป็นการค้นหาคำแบบใช้เงื่อนไขของ Perl regular expression

[user1@devel tmp]$ time grep -P "(jan|feb)" test-data.txt > /dev/null
real    0m2.063s
user    0m2.143s
sys     0m0.358s

ลดลงเวลาลงเกือบ 10 เท่า เมื่อเปรียบเทียบกับ grep -E แถมไม่ต้องยุ่งยากกับการเขียนโปรแกรมมากนัก

Leave a Reply

Your email address will not be published.