ช่วงนี้รับงาน เพื่อเขียนโปรแกรมดึงข้อมูลจาก 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 แถมไม่ต้องยุ่งยากกับการเขียนโปรแกรมมากนัก