Chez DailyWatch, notre panneau « vidéos associées » a commencé par une simple requête SQLite. Elle effectuait une jointure sur trois tables, comptait les tags en commun et renvoyait une liste classée. Pour un petit catalogue, cela suffisait. Une vidéo de cuisine avec les tags « italian » et « pasta » faisait apparaître d'autres vidéos avec les mêmes tags, et les utilisateurs cliquaient. Le résultat semblait pertinent parce que les métadonnées étaient propres et la bibliothèque peu profonde.
Puis le catalogue a grandi, et les attentes de l'audience ont évolué. Les gens ne voulaient pas simplement plus de vidéos avec des tags identiques. Ils voulaient le clip que quarante pour cent des spectateurs regardaient immédiatement après celui en cours. Ils voulaient la chaîne de niche qui continuait d'apparaître lors des mêmes sessions de visionnage nocturnes, même si sa description ne mentionnait rien de la vidéo de départ et que ses tags étaient quasi inexistants. Il s'agit de schémas comportementaux, et non de correspondances de métadonnées. SQLite ne pouvait pas les exprimer sans dégénérer en un nid ingérable de self-joins et d'expressions de table communes (CTE) récursives. Chaque nouveau signal que nous tentions de modéliser, qu'il s'agisse du co-visionnage ou de l'adjacence de session, ajoutait de la latence et une charge mentale accrue. Nous avions un problème de graphe compressé dans un habit relationnel.
J'ai déplacé la couche de recommandation vers Apache AGE.
Apache AGE est une extension PostgreSQL qui ajoute des requêtes de graphe openCypher à la base de données que vous utilisez déjà. Ce n'est pas un serveur distinct. Ce n'est pas un sidecar. Il s'exécute à l'intérieur de Postgres, ce qui signifie que nous avons pu construire un réseau de co-visionnage sans avoir à mettre en place un cluster Neo4j dédié ou à apprendre un tout nouveau guide opérationnel. Pour une petite équipe sans ingénieur en fiabilité des bases de données, cette distinction était cruciale.
Pourquoi une extension est préférable à une nouvelle base de données
Ajouter une base de données de graphes à votre stack est facile sur un tableau blanc, mais coûteux en production. Vous avez besoin de nouveaux tableaux de bord de surveillance, de nouvelles procédures de sauvegarde, de nouveaux pools de connexion et d'une nouvelle logique de basculement (failover). AGE contourne tout cela car il vit à l'intérieur de votre instance Postgres existante.
Il y a quatre raisons pratiques pour lesquelles cela a fonctionné pour nous.
- Pas de nouvelle infrastructure. Comme AGE est une extension, votre planning
pg_dumpactuel, vos réplicas existants et vos contrôles de santé Postgres standards continuent de fonctionner. Vous n'avez pas besoin de convaincre l'équipe des opérations de surveiller un autre magasin de données. - Charges de travail mixtes en une seule requête. AGE vous permet d'écrire du Cypher à l'intérieur de SQL. Vous pouvez effectuer un parcours de graphe pour trouver des vidéos candidates, puis joindre cet ensemble de résultats à votre table relationnelle
userspour appliquer des restrictions de contenu régionales, ou à une table relationnellesponsorshipspour déprioriser certaines chaînes. Un seul aller-retour. Deux langages de requête qui coopèrent. - Portabilité. Cypher est un langage de requête de graphe ouvert et bien documenté. Si DailyWatch dépasse les capacités d'AGE et doit migrer vers Neo4j ou Memgraph plus tard, la logique de requête est transférable avec un minimum de réécriture. Vous n'êtes pas prisonnier d'un dialecte propriétaire.
- Compatibilité. Comme les données résident finalement dans PostgreSQL, vos outils PHP ou Python existants ne changent pas. Vous vous connectez avec le même pilote, gérez les mêmes chaînes de connexion et récupérez les lignes de la même manière. La logique de graphe se situe dans la couche de requête, pas dans la couche applicative.
Modéliser le co-visionnage
L'implémentation est directe. Nous avons défini des nœuds pour les entités qui nous intéressaient : Video et Channel. Nous avons ensuite défini des arêtes pour les relations entre elles. Une arête PUBLISHED lie un Channel à une Video. Une arête CO_VIEWED lie une Video à une autre, portant une propriété weight qui représente la fréquence à laquelle les deux vidéos sont apparues dans la même session de visionnage.
Ce modèle capture quelque chose que le SQL basé sur les tags ne peut pas faire : la structure implicite
