DailyWatch में, हमारा "related videos" पैनल एक साधारण SQLite क्वेरी के साथ शुरू हुआ था। इसने तीन टेबल्स को जॉइन किया, ओवरलैपिंग टैग्स को गिना, और एक रैंक की गई लिस्ट वापस की। एक छोटे कैटलॉग के लिए, इतना काफी था। "italian" और "pasta" टैग वाला एक कुकिंग वीडियो उन्हीं टैग्स वाले अन्य वीडियो सामने ले आता था, और यूजर्स उन पर क्लिक करते थे। आउटपुट प्रासंगिक लगता था क्योंकि मेटाडेटा साफ था और लाइब्रेरी छोटी (shallow) थी।
फिर कैटलॉग बढ़ा, और दर्शकों की उम्मीदें बदल गईं। लोग केवल समान टैग वाले और वीडियो नहीं चाहते थे। वे वह क्लिप चाहते थे जिसे चालीस प्रतिशत दर्शक वर्तमान वीडियो के तुरंत बाद देखते थे। वे वह नीश (niche) चैनल चाहते थे जो उन्हीं देर रात के वॉचिंग सेशन्स में बार-बार सामने आता था, भले ही उसके डिस्क्रिप्शन में शुरुआती वीडियो के बारे में कुछ भी न लिखा हो और उसके टैग्स बहुत कम हों। ये व्यवहारिक पैटर्न (behavioral patterns) हैं, न कि मेटाडेटा मैच। SQLite इन्हें बिना सेल्फ-जॉइन्स (self-joins) और रिकर्सिव कॉमन टेबल एक्सप्रेशंस (recursive common table expressions) के एक रखरखाव न किए जा सकने वाले जाल में उलझे व्यक्त नहीं कर सकता था। हर नया सिग्नल जिसे हमने मॉडल करने की कोशिश की, चाहे वह को-व्यूअरशिप (co-viewership) हो या सेशन एडजेसेंसी (session adjacency), वह लेटेंसी (latency) और मानसिक ओवरहेड (mental overhead) बढ़ा देता था। हमारे पास एक ग्राफ समस्या थी जिसे रिलेशनल (relational) ढांचे में समेटने की कोशिश की जा रही थी।
मैंने रिकमेंडेशन लेयर को Apache AGE पर स्थानांतरित कर दिया।
Apache AGE एक PostgreSQL एक्सटेंशन है जो आपके द्वारा पहले से चलाए जा रहे डेटाबेस में openCypher ग्राफ क्वेरीज़ जोड़ता है। यह कोई अलग सर्वर नहीं है। यह कोई साइडकार (sidecar) नहीं है। यह Postgres के अंदर चलता है, जिसका अर्थ था कि हम एक समर्पित Neo4j क्लस्टर स्थापित किए बिना या पूरी तरह से नया ऑपरेशनल प्लेबुक सीखे बिना एक को-व्यू नेटवर्क बना सकते थे। डेटाबेस रिलायबिलिटी इंजीनियर के बिना एक छोटी टीम के लिए, यह अंतर बहुत मायने रखता था।
क्यों एक एक्सटेंशन एक नए डेटाबेस से बेहतर है
अपने स्टैक में ग्राफ डेटाबेस जोड़ना व्हाइटबोर्ड पर आसान है लेकिन प्रोडक्शन में महंगा है। आपको नए मॉनिटरिंग डैशबोर्ड, नई बैकअप प्रक्रियाएं, नए कनेक्शन पूल और नए फेलओवर लॉजिक की आवश्यकता होती है। AGE इन सब से बच जाता है क्योंकि यह आपके मौजूदा Postgres इंस्टेंस के अंदर रहता है।
इसके हमारे लिए काम करने के चार व्यावहारिक कारण हैं।
- कोई नया इंफ्रास्ट्रक्चर नहीं। क्योंकि AGE एक एक्सटेंशन है, आपका वर्तमान
pg_dumpशेड्यूल, आपके मौजूदा रेप्लिका और आपके मानक Postgres हेल्थ चेक सभी काम करना जारी रखते हैं। आपको ऑपरेशन्स टीम को एक और डेटा स्टोर की देखभाल करने के लिए मनाने की आवश्यकता नहीं है। - एक ही क्वेरी में मिश्रित वर्कलोड। AGE आपको SQL के अंदर Cypher लिखने की अनुमति देता है। आप कैंडिडेट वीडियो खोजने के लिए ग्राफ ट्रावर्सल (graph traversal) चला सकते हैं, फिर क्षेत्रीय कंटेंट प्रतिबंधों को लागू करने के लिए उस रिजल्ट सेट को अपनी रिलेशनल
usersटेबल के साथ, या कुछ चैनलों को कम प्राथमिकता देने के लिए एक रिलेशनलsponsorshipsटेबल के साथ जॉइन कर सकते हैं। एक राउंड-ट्रिप। दो क्वेरी भाषाओं का सहयोग। - पोर्टेबिलिटी। Cypher एक ओपन और अच्छी तरह से प्रलेखित ग्राफ क्वेरी भाषा है। यदि DailyWatch AGE से बड़ा हो जाता है और बाद में Neo4j या Memgraph पर माइग्रेट करने की आवश्यकता होती है, तो न्यूनतम रीराइटिंग के साथ क्वेरी लॉजिक ट्रांसफर हो जाता है। आप किसी प्रोप्राइटरी डायलेक्ट (proprietary dialect) में बंधे नहीं हैं।
- संगतता (Compatibility)। क्योंकि डेटा अंततः PostgreSQL में रहता है, आपके मौजूदा PHP या Python टूलिंग में कोई बदलाव नहीं होता है। आप उसी ड्राइवर से कनेक्ट करते हैं, उन्हीं कनेक्शन स्ट्रिंग्स को संभालते हैं, और उसी तरह से रो (rows) प्राप्त करते हैं। ग्राफ लॉजिक क्वेरी लेयर में होता है, एप्लिकेशन लेयर में नहीं।
को-व्यूअरशिप (Co-Viewership) को मॉडल करना
इसका कार्यान्वयन सीधा है। हमने उन एंटिटीज (entities) के लिए नोड्स (nodes) परिभाषित किए जिनकी हमें आवश्यकता थी: Video और Channel| हमने फिर उनके बीच के संबंधों के लिए एडजेस (edges) परिभाषित किए। एक PUBLISHED एज एक Channel को Video से जोड़ता है। एक CO_VIEWED एज एक Video को दूसरे से जोड़ता है, जिसमें एक weight प्रॉपर्टी होती है जो यह दर्शाती है कि दो वीडियो कितनी बार एक ही वॉचिंग सेशन में दिखाई दिए।
यह मॉडल कुछ ऐसा कैप्चर करता है जो टैग-आधारित SQL नहीं कर सकता: अंतर्निहित संरचना (implicit structure)
