پرسوجو از روابط ویدئویی با Apache AGE در Postgres
پایگاههای داده رابطهای در مدیریت روابط عمیق با چالش روبرو هستند.
ما در TrendVidStream، کاتالوگی از عناوین استریم را در هشت منطقه مدیریت میکنیم. ما در ابتدا از SQLite به همراه FTS5 استفاده میکردیم. این ترکیب برای جستجوی تماممتن (full-text search) و استقرارهای ساده بهخوبی عمل میکرد.
مشکل زمانی شروع شد که کاربران سوالات پیچیدهای میپرسیدند. آنها میخواستند بدانند: «چه چیزهای دیگری در فاصله دو یا سه گام (hop) از این فیلم هیجانانگیز با این کارگردان و این بازیگران خاص قرار دارد؟»
در SQL، این کار مستلزم چندین self-join است. هر گام اضافی، نگهداری پرسوجو را دشوارتر و اجرای آن را کندتر میکند. گسترش بیش از حد اتصالات (join fan-out) به یک کابوس تبدیل میشود.
ما این مشکل را با افزودن یک لایه گراف با استفاده از افزونه Apache AGE روی PostgreSQL حل کردیم.
دلایل کارآمد بودن این رویکرد دوگانه عبارتند از:
• شما PostgreSQL را حفظ میکنید. از همان اتصالات، تراکنشها و ابزارهای پشتیبانگیری استفاده میکنید. نیازی به یک پایگاه داده مجزا مانند Neo4j ندارید. • شما دادههای گراف و رابطهای را با هم ترکیب میکنید. میتوانید پرسوجوهای Cypher را اجرا کرده و نتایج آنها را با جداول استاندارد SQL ترکیب (join) کنید. • شما عمق متغیر را بهراحتی مدیریت میکنید. یافتن اتصالات در فاصله یک تا سه گام، در Cypher یک دستور ساده است. • شما سادگی را حفظ میکنید. گراف، نمایشی (projection) از دادههای شماست، نه یک منبع حقیقت (source of truth) مجزا.
مدل ما از چهار برچسب رأس (vertex label) استفاده میکند:
- Video
- Person
- Platform
- Region
ما از انواع یالهای (edge types) خاصی مانند SIMILAR_TO، WORKED_ON و AVAILABLE_IN استفاده میکنیم.
یک درس حیاتی: همیشه نقاط ورود خود را ایندکس کنید. ما ویژگی ext_id را روی رأسهای Video ایندکس میکنیم. بدون این کار، هر پیمایش (traversal) با یک اسکن ترتیبی (sequential scan) کند شروع میشود.
نتیجه، یک پرسوجوی تمیز و خوانا برای سیستمهای پیشنهاددهنده است:
SELECT * FROM cypher('discovery', $$ MATCH (seed:Video {ext_id: 'vid_8842'}) MATCH (seed)-[:SIMILAR_TO|WORKED_ON*1..3]-(rec:Video)-[:AVAILABLE_IN]->(:Region {code: 'DE'}) WHERE rec.ext_id <> 'vid_8842' RETURN DISTINCT rec.ext_id, rec.title, rec.year LIMIT 24 $$) AS (ext_id agtype, title agtype, year agtype);
این پرسوجو ویدئوهای مرتبط را در فاصله سه گام که در آلمان در دسترس هستند، پیدا میکند. در SQL، این کار مستلزم کوهی از joinها خواهد بود، اما در Cypher، یک الگوی ساده است.
ما SQLite را برای جستجوی متن نگه داشتیم و از AGE برای مدیریت اتصالات استفاده کردیم. هر ابزار کاری را که در آن بهترین است، انجام میدهد.
