ساخت پرسوجوهای رابطهای ویدئویی مبتنی بر گراف با Apache AGE
سنگینترین پرسوجوی ما، یک پنل سادهی «نمایش ویدئوهای مرتبط» بود.
ما در ViralVidVault روندهای ویدئویی را دنبال میکنیم. متوجه شدیم که یافتن ویدئوهای مرتبط از طریق کانالهای مشترک یا نشستهای مشاهدهی همزمان (co-viewed sessions)، عملکرد پایگاه داده ما را از کار میانداخت. ما استفاده از SQLite را با joinهای بازگشتی (recursive joins) امتحان کردیم. این روش برای یک گام (one hop) جواب میداد، اما در دو گام، حجم دادهها به شدت منفجر میشد. یک پرسوجو باعث ایجاد صدها هزار ردیف میشد و پردازشهای ما با خطای زمان انتظار (timeout) مواجه میشدند.
دادهها ماهیت گراف دارند. ما سعی داشتیم آنها را به زور در قالب جدول جای دهیم و بهای آن را میپرداختیم.
ما لایهی روابط را به Apache AGE منتقل کردیم. این یک افزونهی openCypher برای PostgreSQL است. ما اپلیکیشن PHP 8.4 و ذخیرهساز SQLite خود را حفظ کردیم.
نتایج: • تأخیر (latency) پنل مرتبط از ۹۰۰ میلیثانیه به زیر ۴۰ میلیثانیه کاهش یافت. • پیمایشهای (traversals) پیچیدهی دوگامی اکنون تنها در حد تکرقمی میلیثانیه زمان میبرند. • بار عملیاتی ما ثابت ماند، زیرا AGE درون Postgres اجرا میشود.
چرا به جای یک پایگاه داده گراف مستقل، از Apache AGE استفاده کنیم؟
۱. سادگی عملیاتی شما نیازی به یک پایگاه داده جدید برای پشتیبانگیری یا ایمنسازی ندارید. AGE از تنظیمات موجود Postgres، استخرهای اتصال (connection pools) و قوانین امنیتی شما استفاده میکند.
۲. پرسوجوهای گراف بومی در SQL، مسیرهای با طول متغیر نیازمند بازگشت (recursion) پیچیده هستند. در Cypher، شما آنها را به صورت الگوهای ساده مینویسید. یک بلوک SQL بازگشتی ۴۰ خطی، به یک پرسوجوی Cypher ۶ خطی تبدیل شد.
۳. عملکرد بهتر یک موتور گراف، مجاورت (adjacency) را ایندکس میکند. این موتور از گسترش مسیرهایی که مطابقت ندارند جلوگیری میکند. این کار مانع از پخش شدن بیش از حد دادهها (data fan-out) میشود که سیستم قبلی ما را از کار انداخته بود.
یک درس کلیدی از مهاجرت ما: همیشه ویژگیهای نقطه ورود (entrypoint properties) خود را ایندکس کنید. اگر شناسهای (ID) را که برای شروع یک پیمایش استفاده میکنید ایندکس نکنید، AGE یک اسکن کامل (full scan) انجام خواهد داد. این کار حتی بهترین پرسوجوی گراف را نیز کند میکند.
ما از گراف به عنوان یک مدل خواندن (read model) استفاده میکنیم. دادههای خام ما در SQLite باقی میمانند. ما از یک اسکریپت Python برای همگامسازی این دو استفاده میکنیم. این کار باعث میشود گراف ما سریع، سبک و بازسازی آن آسان باشد.
اگر پرسوجوهای SQL بازگشتی شما بیش از حد پیچیده میشوند، با مدل رابطهای نجنگید. یک تصویر گرافیکی (graph projection) کوچک در کنار ذخیرهساز فعلی خود بسازید.
