การสร้างคิวรีความสัมพันธ์ของวิดีโอแบบใช้กราฟด้วย Apache AGE
คิวรีที่กินทรัพยากรมากที่สุดของเราคือแผง "แสดงวิดีโอที่เกี่ยวข้อง" แบบง่ายๆ
ที่ ViralVidVault เราติดตามเทรนด์วิดีโอ เราพบว่าการค้นหาวิดีโอที่เกี่ยวข้องผ่านช่องที่แชร์ร่วมกันหรือเซสชันการรับชมร่วมกันนั้นทำลายประสิทธิภาพของฐานข้อมูลเรา เราพยายามใช้ SQLite ร่วมกับ recursive joins ซึ่งมันใช้งานได้ดีสำหรับการเชื่อมต่อแบบหนึ่งระดับ (one hop) แต่พอเป็นสองระดับ (two hops) ข้อมูลก็ระเบิดออกมา คิวรีเดียวสร้างแถวข้อมูลหลายแสนแถว ทำให้ worker ของเราเริ่มเกิดปัญหา timeout
ข้อมูลนี้คือกราฟ แต่เราพยายามฝืนยัดมันลงในตาราง และนั่นคือสิ่งที่เราต้องชดใช้
เราจึงย้ายเลเยอร์ความสัมพันธ์ไปไว้ที่ Apache AGE ซึ่งเป็นส่วนขยาย openCypher สำหรับ PostgreSQL โดยที่เรายังคงใช้แอป PHP 8.4 และที่เก็บข้อมูล SQLite เดิมของเราไว้
ผลลัพธ์ที่ได้: • ความหน่วง (latency) ของแผงวิดีโอที่เกี่ยวข้องลดลงจาก 900ms เหลือไม่ถึง 40ms • การท่องไปในกราฟ (traversal) แบบสองระดับที่ซับซ้อน ใช้เวลาเพียงหลักหน่วยมิลลิวินาทีเท่านั้น • ภาระงานด้านการปฏิบัติการ (operational workload) ของเรายังคงเท่าเดิม เพราะ AGE ทำงานอยู่ภายใน Postgres
ทำไมต้องใช้ Apache AGE แทนที่จะใช้ฐานข้อมูลกราฟแบบ standalone?
ความเรียบง่ายในการปฏิบัติการ (Operational Simplicity) คุณไม่จำเป็นต้องมีฐานข้อมูลใหม่เพื่อสำรองข้อมูลหรือรักษาความปลอดภัย AGE ใช้การตั้งค่า Postgres, connection pools และกฎความปลอดภัยเดิมที่คุณมีอยู่แล้ว
การคิวรีแบบกราฟโดยตรง (Native Graph Queries) ใน SQL การหาเส้นทางที่มีความยาวไม่คงที่ (variable-length paths) ต้องใช้การทำ recursion ที่ซับซ้อน แต่ใน Cypher คุณสามารถเขียนมันเป็นรูปแบบ (patterns) ง่ายๆ ได้ บล็อก SQL แบบ recursive 40 บรรทัด กลายเป็นคิวรี Cypher เพียง 6 บรรทัด
ประสิทธิภาพที่ดีกว่า เอนจินกราฟจะทำดัชนี (index) ความสัมพันธ์ที่อยู่ติดกัน (adjacency) และจะหยุดขยายเส้นทางที่ไม่ตรงตามเงื่อนไข สิ่งนี้ช่วยป้องกันปัญหาข้อมูลขยายตัวแบบทวีคูณ (data fan-out) ที่เคยทำให้ระบบเดิมของเราล่ม
บทเรียนสำคัญจากการย้ายระบบของเรา: จงทำดัชนี (index) ให้กับคุณสมบัติที่เป็นจุดเริ่มต้น (entrypoint properties) เสมอ หากคุณไม่ทำดัชนีให้กับ ID ที่ใช้ในการเริ่ม traversal ตัว AGE จะทำการสแกนข้อมูลทั้งหมด (full scan) ซึ่งจะทำให้แม้แต่คิวรีแบบกราฟที่ดีที่สุดก็ช้าลงได้
เราใช้กราฟเป็นโมเดลสำหรับการอ่าน (read model) โดยที่ข้อมูลดิบของเรายังคงอยู่ใน SQLite เราใช้สคริปต์ Python ในการซิงค์ข้อมูลทั้งสองส่วนเข้าด้วยกัน วิธีนี้ช่วยให้กราฟของเราทำงานได้รวดเร็ว น้ำหนักเบา และสร้างใหม่ได้ง่าย
หากคิวรี SQL แบบ recursive ของคุณเริ่มซับซ้อนเกินไป อย่าฝืนสู้กับโมเดลเชิงสัมพันธ์ (relational model) เลย ให้สร้าง graph projection ขนาดเล็กควบคู่ไปกับที่เก็บข้อมูลปัจจุบันของคุณแทน
