ทำความรู้จักกับ Bloom Filters: โครงสร้างข้อมูลแบบความน่าจะเป็นที่ขับเคลื่อน Instagram, Google และระบบขนาดใหญ่

8 นาที 6 views บันทึกเป็น PDF
ทำความรู้จักกับ Bloom Filters: โครงสร้างข้อมูลแบบความน่าจะเป็นที่ขับเคลื่อน Instagram, Google และระบบขนาดใหญ่

Bloom Filter คืออะไรและทำไมโปรแกรมเมอร์ต้องรู้จัก...

Bloom Filter คืออะไรและทำไมโปรแกรมเมอร์ต้องรู้จัก

เวลาเราสร้างแอปที่มีผู้ใช้งานจำนวนมาก เช่น Instagram ปัญหาคลาสสิกคือการเช็คว่า "ชื่อผู้ใช้" (Username) นี้มีคนใช้ไปหรือยัง ถ้าเราปล่อยให้แอปไปถามฐานข้อมูลทุกครั้งที่คนพิมพ์ชื่อ มันจะกลายเป็นภาระหนักของระบบจนทำงานช้าลง เราเลยต้องมีตัวช่วยที่เรียกว่า Bloom Filter (โครงสร้างข้อมูลแบบน่าจะเป็น) เข้ามาจัดการเรื่องนี้แทน

ลองจินตนาการว่าคุณเป็นพนักงานหน้าประตูคลับที่มีรายชื่อแขก 500 ล้านคน ถ้ามีคนมาถามว่าเขาเข้าได้ไหม การเปิดสมุดรายชื่อดูทีละหน้าคงเสียเวลามาก แทนที่จะทำแบบนั้น คุณอาจจะใช้ แผ่นป้ายพิเศษ ที่บอกได้ทันทีว่า "คนนี้ไม่มีชื่อในลิสต์แน่นอน" หรือ "คนนี้อาจจะมีชื่อในลิสต์นะ ต้องไปเช็คในสมุดอีกที" นี่คือหัวใจของเทคโนโลยีนี้ครับ

มันคือโครงสร้างข้อมูลที่ช่วยให้เราตอบคำถามได้เร็วมากโดยไม่ต้องไปค้นในฐานข้อมูล (ที่เก็บข้อมูลถาวร) ทุกครั้ง มันไม่ได้บอกความจริงได้ 100% ในทุกกรณี แต่มันบอกเราได้ชัวร์ๆ ว่า "ไม่มี" และถ้ามันบอกว่า "มี" เราค่อยไปเช็คกับฐานข้อมูลจริงๆ อีกที วิธีนี้ช่วยลดการทำงานของฐานข้อมูลลงได้มหาศาลครับ

ส่วนประกอบสำคัญของ Bloom Filter

โครงสร้างของมันมีแค่สองอย่างหลักๆ คือ Bit Array (แถวของข้อมูลบิตที่มีแค่ 0 กับ 1) และ Hash Function (ฟังก์ชันแปลงข้อมูลให้เป็นตัวเลข) โดยเราจะเริ่มจากกำหนดขนาดของ Bit Array ไว้ก่อน แล้วตั้งค่าทุกตำแหน่งให้เป็น 0 ทั้งหมด เพื่อเตรียมรอรับข้อมูลที่จะเข้ามา

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

จำไว้ว่าเราไม่ได้เก็บตัวข้อมูลจริงๆ ไว้ในนี้เลย เราเก็บแค่ "ร่องรอย" ของมันผ่านตัวเลข 1 ที่ถูกปักไว้ในตำแหน่งต่างๆ เท่านั้น ทำให้มันประหยัดพื้นที่หน่วยความจำมากเมื่อเทียบกับการเก็บชื่อผู้ใช้ยาวๆ หลายล้านชื่อไว้ในระบบแบบเดิม

วิธีเพิ่มข้อมูลและการตรวจสอบ

การเพิ่มข้อมูลทำได้โดยการนำชื่อไปผ่าน Hash Function หลายๆ ตัวเพื่อหาตำแหน่งที่จะปักหมุด แล้วเปลี่ยนค่า 0 เป็น 1 ในตำแหน่งนั้นๆ สมมติเรามี 3 ฟังก์ชัน ข้อมูลหนึ่งชิ้นจะไปปักหมุด 3 จุดใน Bit Array ทำให้เกิด "ลายเซ็น" เฉพาะตัวขึ้นมาครับ

สำหรับการตรวจสอบ เราก็นำชื่อเดิมไปผ่าน Hash Function ชุดเดิมเพื่อให้ได้ตำแหน่งเดียวกัน ถ้าทุกตำแหน่งที่ได้มีค่าเป็น 1 ทั้งหมด ระบบจะตอบว่า "อาจจะมีอยู่" แต่ถ้าเจอแค่เลข 0 แม้แต่ตำแหน่งเดียว ระบบจะตอบได้ทันทีว่า "ไม่มีแน่นอน" ซึ่งเป็นคำตอบที่เชื่อถือได้ 100% ครับ

// ตัวอย่างจำลองการทำงานด้วยแนวคิดของ Bloom Filter
int[] bitArray = new int[10]; // สร้างแถวข้อมูลขนาด 10 ช่อง

void add(string item) {
    bitArray[hash1(item) % 10] = 1;
    bitArray[hash2(item) % 10] = 1;
}

bool check(string item) {
    // ถ้าเจอ 0 ในตำแหน่งใดตำแหน่งหนึ่ง ให้ตอบว่าไม่มีแน่นอน
    if (bitArray[hash1(item) % 10] == 0) return false;
    if (bitArray[hash2(item) % 10] == 0) return false;
    return true; // อาจจะมีอยู่
}

โค้ดส่วนนี้แสดงการสร้าง bitArray เพื่อเก็บสถานะ และฟังก์ชัน add ที่ใช้ hash1 และ hash2 เพื่อปักหมุดในตำแหน่งต่างๆ ส่วนฟังก์ชัน check จะคอยเช็คว่าตำแหน่งที่คำนวณได้มีค่าเป็น 1 หรือไม่ ถ้าเจอ 0 ปุ๊บจะรีบตอบกลับทันทีว่าไม่มี

ผลลัพธ์ที่ควรเห็นคือ เมื่อรันคำสั่ง check("new_user") ถ้าชื่อนั้นไม่เคยถูกใส่เข้าไปใน add ฟังก์ชันจะคืนค่า false ทันทีโดยไม่ต้องค้นหาข้อมูลอื่นต่อ ทำให้ประหยัดเวลาการทำงานได้อย่างมากครับ

ทำความเข้าใจเรื่อง False Positive

คำว่า False Positive (การทายผิดว่ามี ทั้งที่ไม่มีจริง) คือจุดอ่อนเดียวของระบบนี้ มันเกิดขึ้นเมื่อข้อมูลใหม่ที่ใส่เข้ามา ดันไปสุ่มเจอตําแหน่งที่มีคนอื่นจองไว้แล้วจนครบทุกจุด ทำให้ระบบเข้าใจผิดว่าข้อมูลนั้นถูกเพิ่มเข้ามาแล้ว ทั้งที่จริงๆ แล้วไม่ใช่

ข้อควรระวังคือ เราไม่สามารถลบข้อมูลออกจาก Bloom Filter แบบปกติได้ เพราะถ้าเราไปเปลี่ยน 1 กลับเป็น 0 ในตำแหน่งที่ข้อมูลทับซ้อนกันอยู่ เราจะเผลอลบข้อมูลของคนอื่นหายไปจากระบบด้วย นี่คือเหตุผลว่าทำไมมันถึงเหมาะกับข้อมูลที่มีแต่การเพิ่ม แต่ไม่มีการลบครับ

เราจัดการเรื่องนี้ได้ด้วยการคำนวณขนาดของ Bit Array ให้ใหญ่พอและใช้จำนวน Hash Function ที่เหมาะสม เพื่อลดโอกาสที่ข้อมูลจะมาทับซ้อนกันจนเกิดความผิดพลาดบ่อยเกินไป ยิ่ง Bit Array ใหญ่ โอกาสพลาดก็น้อยลง แต่ก็จะแลกมาด้วยการใช้หน่วยความจำที่เพิ่มขึ้นครับ

การนำไปใช้งานจริงในระบบขนาดใหญ่

บริษัทอย่าง Google หรือ Instagram ใช้ Bloom Filter เพื่อกรองคำขอที่ไม่จำเป็นออกไปก่อนจะถึงฐานข้อมูล เช่น การเช็คว่า URL ที่คนพิมพ์เข้ามาเป็นเว็บอันตรายหรือไม่ หรือการเช็คว่าชื่อผู้ใช้ถูกจองไปหรือยัง ถ้า Filter บอกว่าไม่มี เราก็ปฏิเสธคำขอนั้นได้ทันทีโดยไม่ต้องเสียเวลาไปค้นในดิสก์

มันเป็นตัวช่วยที่ทำให้ระบบมีความ Scalability (ความสามารถในการรองรับการขยายตัว) ได้ดีขึ้นมาก เพราะแทนที่จะต้องรอฐานข้อมูลทำงานหนักๆ ทุกครั้ง เราจ่ายค่าพลังประมวลผลเพียงเล็กน้อยเพื่อถาม Bloom Filter ก่อนเสมอ ถ้ามันบอกว่า "น่าจะใช่" ค่อยไปถามฐานข้อมูลหลักอีกที

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

สรุป: เมื่อไหร่ที่ควรใช้ Bloom Filter

สรุปสั้นๆ คือใช้เมื่อคุณต้องการความเร็วในการเช็คข้อมูล และยอมรับได้ว่าอาจจะมีข้อผิดพลาดบ้างในบางครั้ง (ซึ่งเราแก้ได้ด้วยการไปเช็คฐานข้อมูลอีกที) ห้ามใช้เมื่อคุณต้องการความแม่นยำ 100% หรือเมื่อระบบของคุณต้องมีการลบข้อมูลบ่อยๆ เพราะมันไม่ได้ถูกออกแบบมาเพื่อการนั้นครับ

ตัวอย่างการใช้งานที่เห็นภาพชัดที่สุดคือ "ระบบกรองการเข้าถึงข้อมูล" ก่อนจะไปถึงฐานข้อมูลหนักๆ ถ้าคุณกำลังทำโปรเจกต์ Portfolio หรือระบบที่เน้นการอ่านข้อมูลเป็นหลัก ลองนำ Bloom Filter ไปติดตั้งดูครับ มันจะทำให้ระบบของคุณดูเป็นมืออาชีพและทำงานได้เร็วกว่าคนอื่นแน่นอน

หัวใจสำคัญคือการเลือกขนาดของ Bit Array ให้สมดุลกับจำนวนข้อมูลที่จะเก็บ ถ้าคุณเป็นมือใหม่ ให้เริ่มจากการลองเขียนโค้ดจำลองการทำงานดู แล้วค่อยๆ ปรับจูนจำนวน Hash Function ให้เหมาะสม คุณจะได้เรียนรู้ทั้งเรื่องโครงสร้างข้อมูลและวิธีการประหยัดทรัพยากรของระบบไปพร้อมๆ กันครับ


ที่มา: Bloom Filters Explained: The Probabilistic Data Structure Powering Instagram, Google, and High-Scale Systems — freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

ทำไมการทำโปรเจกต์จริงถึงสำคัญกว่าการดูคลิปสอน สำหรับนักศึกษาและมือใหม่หัดเขียนโค้ด

ทำไมการทำโปรเจกต์จริงถึงสำคัญกว่าการดูคลิปสอน สำหรับนักศึกษาและมือใหม่หัดเขียนโค้ด

เลิกติดกับดักการดูคลิปสอน (Tutorial) แล้วมาเริ่มทำโปรเจกต์จริงกันดีกว่า เรียนรู้วิธีแก้บั๊ก การใช้ Git และการเลือกเครื่องมือให้เหมาะกับงาน เพื่อก้าวสู่การเป็นโปรแกรมเมอร์มืออาชีพ

ที่มา: DEV Community

1 hour ago 9 นาที
4 views
เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เรียนรู้วิธีเขียนแอป Flutter เชื่อมต่อ Meta Smart Glasses ให้ทำงานเร็ว ไม่กระตุก ด้วยการวางสถาปัตยกรรมโค้ดและการจัดการข้อมูลแบบมือโปรที่มือใหม่ทำตามได้จริง

ที่มา: DEV Community

9 hours ago 10 นาที
5 views
เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

อยากทำระบบ Real-Time แต่ไม่รู้จะเลือกใช้ Polling, SSE หรือ WebSocket ดี? มาดูวิธีเลือกใช้ให้เหมาะกับงาน เพื่อให้แอปของคุณทำงานลื่นไหลและประหยัดทรัพยากรเซิร์ฟเวอร์

ที่มา: DEV Community

13 hours ago 10 นาที
5 views