Retour aux projets
20 déc. 2025 • Projet

REngine : un moteur de recommandation sur graphe

Moteur de recommandation qui passe les données d'une boutique Sylius / MySQL dans un graphe Neo4j, calcule affinités et similarités entre clients, et sert les suggestions via FastAPI.

PythonNeo4jFastAPIPandasGraph Data Science
Contexte
Projet perso, toujours en cours : recommander des produits à partir de l'historique d'achat d'une boutique Sylius / MySQL.
Mon rôle
Tout le projet : ETL MySQL vers Neo4j, calcul des affinités et des similarités, API de recommandation.
Résultat
Un prototype qui répond en 19 ms en moyenne en local, grâce aux liens d'affinité pré-calculés dans le graphe.

L’idée

Les données d’une boutique e-commerce sont relationnelles : des clients, des produits, des commandes. Pour recommander, la question intéressante est justement la relation : « les clients qui ressemblent à celui-ci, qu’ont-ils acheté d’autre ? ». En SQL, ça devient vite une suite de jointures. Dans un graphe, c’est un parcours.

REngine passe donc les données d’une boutique Sylius (MySQL) dans Neo4j, et calcule les recommandations dans le graphe.

Le pipeline

Quatre étapes, chacune dans son service :

  1. Synchronisation : migration des clients, produits et commandes de MySQL vers Neo4j, en filtrant le bruit (voir plus bas).
  2. Affinités : chaque client est relié aux produits qui l’intéressent (INTERESTED_IN).
  3. Similarités : les clients aux profils proches sont reliés entre eux (SIMILAR_TO).
  4. API : les recommandations sont servies en REST par FastAPI.

Le code est découpé en migrators, services et repositories, ce qui permet de faire évoluer une étape sans toucher aux autres.

Un client relié à ses produits d'intérêt dans le graphe
Un profil client et ses produits d'intérêt (INTERESTED_IN)

Le problème : les produits que tout le monde achète

Aux premiers tests, des articles de base (sacs réutilisables, produits du quotidien) reliaient presque tous les clients entre eux. Résultat : des similarités qui ne voulaient rien dire.

La solution : un service d’analyse repère le top 1 % des ventes, leur pose un label CommonProduct et les exclut du calcul des similarités. Les produits offerts ou promotionnels sont aussi écartés, pour ne garder que de vrais choix d’achat.

Calculer la proximité entre clients

Deux clients sont candidats s’ils partagent au moins trois produits. Un premier calcul de similarité se fait en mémoire avec Pandas ; pour aller plus loin, j’utilise l’extension Neo4j Graph Data Science (GDS), qui écrit des relations SIMILAR_TO pondérées directement dans le graphe.

Les suggestions s’appuient ensuite sur le framework GraphAware Recommendation Engine, et sur APOC pour l’analyse de panier.

Le principe : on regarde ce que les clients les plus proches ont acheté, et on le propose.

Éviter les doublons

Une recommandation utile n’est pas une variante du produit déjà vu. Si un client consulte un produit en boîte de 30 gélules, lui proposer la boîte de 60 n’apporte rien : le moteur écarte ces variantes pour proposer autre chose.

Performance

Les liens d’affinité et de similarité sont pré-calculés. Une requête de recommandation n’a donc qu’à parcourir le graphe : 19 ms en moyenne, en local.

Ce que j’en retiens

La suite

C’est un prototype que je continue de mon côté. La prochaine étape est de recalculer affinités et similarités périodiquement, pour intégrer les nouveaux comportements d’achat au fil de l’eau.