Recommandations avec Neo4j et le GraphAware Recommendation Engine

Post on 04-Aug-2015

178 views 0 download

Transcript of Recommandations avec Neo4j et le GraphAware Recommendation Engine

GraphAwareTM

Christophe Willemsen

graphaware.com

@graph_aware

Recommandations avec Neo4j

Construction d’un moteur de recommandation haute-performance

GraphAwareTM

Rapide introductionPourquoi les graphes ?Challenges Business et TechniquesGraphAware Recommendation Engine

A propos

GraphAwareTM

Articles que vous pourriez lireLivres que vous pourriez acheterPersonnes que vous pourriez connaitrePersonnes que vous pourriez rencontrerPersonnes auxquelles vous pourriez présentervotre produit…

Recommandation

GraphAwareTM

Approche contenu (caractéristiques)Filtrage collaboratif (relations utilisateur <-> produit)

Recommandation

GraphAwareTM

Les caractéristiques tout comme les relations peuvent être représentées naturellement dans un graphe.

Bonnes nouvelles

GraphAwareTM

Exemple

IS_OF_GENRE

title: “Love Actually”

Movie

name: “Bob”

User

name: “Comedy”

Genre

RATEDrating: 5

name: “Alice”

Username:

“Romance”

Genre

title: “American Pie”

Movie

IS_OF_GENRE

IS_OF_GENRE

RATEDrating: 5

INTERESTED_IN

rating: 5RATED

GraphAwareTM

Facile à comprendreModélisation naturelleFlexible (schema-free)Temps de requête ultra-rapides

Graphes (Neo4j)

GraphAwareTM

Bien pour un PoC rapideBien pour des petits jeux de donnéesBien pour des logiques relativement simples

Cypher

GraphAwareTM

CypherMATCH (u:User)-[:LIKED]->(m:Movie), (m)<-[:LIKED]-(another:User), (another)-[:LIKED]->(reco:Movie)

WHERE NOT (u)-[:LIKED|DISLIKED]->(reco)

RETURN reco;

GraphAwareTM

Les spécificités d’un moteur de recommandation pour le monde réel sont souvent beaucoup plus complexes.

La réalité

GraphAwareTM

Imaginez que vous construisez la fonction ”personnes que vous pourriez connaître” sur LinkedIn.

Exemple

GraphAwareTM

Après une session de brainstorming, votre équipe définit de la façon suivante comment trouver des personnes que vous pourriez connaître:

Exemple

GraphAwareTM

Contacts en communAmis Facebook en communsContacts email/mobile en communTous les autres contacts email/mobileTravaillé pour la même sociétéEtudié à la même écolePartage le même intérêtVit dans la même ville

Personnes que vous pourriez connaître

GraphAwareTM

Mais c’est seulement le début!

Retournons en arrière et améliorons tout cela.

GraphAwareTM

Plus de contacts en commun = meilleure chance?Même ville / école / société = la taille compte?Qu’en est-t-il des emails qui ne représentent pas une personne ?Et les personnes déjà connectées? Et celles en attente… Et celles rejetées…Et celles ignorées répétivement…

Personnes que vous pourriez connaître

GraphAwareTM

Trouver des “choses” à recommanderServir les recommandations les plus rélévantesMesurer la qualité des recommandationsTime to market / coût du développement

Challenges Business

GraphAwareTM

Performance (real-time!)

Challenges Techniques

GraphAwareTM

Mauvaise Recommandation

GraphAwareTM

Mauvaise Recommandation

GraphAwareTM

Performance (real-time!)SimplicitéFlexibilité

Challenges Techniques

GraphAwareTM

Alors on a sorti une architecture de base open-source d’un moteur de recommandation qui vous aidera à résoudre tous ces challenges.

On l’a fait

GraphAwareTM

plugin Neo4j (utilise GraphAware Framework)vous devez utiliser un langage JVMarchitecture dogmatiqueultra rapideultra flexiblegère toute l’encapsulation

Moteur de recommandation

GraphAwareTM

Un moteur par “raison” de recommandation (core logic)Le moteur effectuée une traversée dans le graphe pour trouver des produits/personnes/..Les moteurs sont assemblés ensemble dans un moteur de haut-niveau

Décisions d’architecture

GraphAwareTM

Exemple

IS_OF_GENRE

title: “Love Actually”

Movie

name: “Bob”

User

name: “Comedy”

Genre

RATEDrating: 5

name: “Alice”

Username:

“Romance”

Genre

title: “American Pie”

Movie

IS_OF_GENRE

IS_OF_GENRE

RATEDrating: 5

INTERESTED_IN

rating: 5RATED

GraphAwareTM

Un moteur par “raison” de recommandation (core logic)Le moteur effectuée une traversée dans le graphe pour trouver des produits/personnes/..Les moteurs sont assemblés ensemble dans un moteur de haut-niveauLes produits trouvés plusieurs fois sont plus rélévantsLa rélévance dépend de la vitesse à laquelle un produit a été trouvé

Décisions d’architecture

GraphAwareTM

Exemple

IS_OF_GENRE

title: “Love Actually”

Movie

name: “Bob”

User

name: “Comedy”

Genre

RATEDrating: 5

name: “Alice”

Username:

“Romance”

Genre

title: “American Pie”

Movie

IS_OF_GENRE

IS_OF_GENRE

RATEDrating: 5

INTERESTED_IN

rating: 5RATED

GraphAwareTM

Un moteur par “raison” de recommandation (core logic)Le moteur effectuée une traversée dans le graphe pour trouver des produits/personnes/..Les moteurs sont assemblés ensemble dans un moteur de haut-niveauLes produits trouvés plusieurs fois sont plus rélévantsLa rélévance dépend de la vitesse à laquelle un produit a été trouvéProduits qui ne doivent pas être recommandés

Décisions d’architecture

GraphAwareTM

Example

IS_OF_GENRE

title: “Love Actually”

Movie

name: “Bob”

User

name: “Comedy”

Genre

RATEDrating: 5

name: “Alice”

Username:

“Romance”

Genre

title: “American Pie”

Movie

IS_OF_GENRE

IS_OF_GENRE

RATEDrating: 5

INTERESTED_IN

rating: 5RATED

GraphAwareTM

Input -> Engine -> RecommandationsScores et Score TransformersBlacklistsFiltersPost-processorsContext (combien, en combien de temps,…?)Loggers

Architecture

GraphAwareTM

En 5 minutes, on va construire un moteur de recommandation qui vous proposera des personnes avec qui vous pourriez vous connecter.

Let’s code

GraphAwareTM

0) Modèle

GraphAwareTM

1) Découverte

GraphAwareTM

public class FriendsInCommon extends SomethingInCommon { @Override public String name() { return "friendsInCommon"; } @Override protected RelationshipType getType() { return FRIEND_OF; } @Override protected Direction getDirection() { return BOTH; }}

GraphAwareTM

2) Score

GraphAwareTM

public class FriendsInCommon extends SomethingInCommon {

@Override protected ScoreTransformer scoreTransformer() { return new ParetoScoreTransformer(100, 10); } @Override public String name() { return "friendsInCommon"; } @Override protected RelationshipType getType() { return FRIEND_OF; } @Override protected Direction getDirection() { return BOTH; }}

GraphAwareTM

3) Post-Process

GraphAwareTM

public class RewardSameLocation extends RewardSomethingShared { @Override protected RelationshipType type() { return LIVES_IN; } @Override protected Direction direction() { return OUTGOING; } @Override protected float scoreValue(Node reco, Node in, Node shared) { return 10; } @Override protected String scoreName() { return "sameLocation"; }}

GraphAwareTM

public class RewardSameLabels implements PostProcessor<Node, Node> { @Override public void postProcess(Recommendations<Node> out, Node in) { Label[] inLabels = toArray(in.getLabels()); for (Recommendation<Node> reco : out.get()) { if (Arrays.equals(inLabels, toArray(reco.getItem().getLabels()))) { reco.add("sameGender", 10); } } }}

GraphAwareTM

4) Filter

GraphAwareTM

... @Override protected List<BlacklistBuilder<Node, Node>> blacklistBuilders() { return asList( new ExistingRelationshipBlacklistBuilder(FRIEND_OF, BOTH) ); } @Override protected List<Filter<Node, Node>> filters() { return asList( new ExcludeSelf() ); }

GraphAwareTM

5) Assemble

GraphAwareTM

public final class FriendsComputingEngine extends Neo4jTopLevelDelegatingEngine { @Override protected List<RecommendationEngine<Node, Node>> engines() { return Arrays.<RecommendationEngine<Node, Node>>asList( new FriendsInCommon(), new RandomPeople() ); } @Override protected List<PostProcessor<Node, Node>> postProcessors() { return Arrays.asList( new RewardSameLabels(), new RewardSameLocation(), new PenalizeAgeDifference() ); } @Override protected List<BlacklistBuilder<Node, Node>> blacklistBuilders() { return Arrays.asList( new ExistingRelationshipBlacklistBuilder(FRIEND_OF, BOTH) ); } @Override protected List<Filter<Node, Node>> filters() { return Arrays.<Filter<Node, Node>>asList( new ExcludeSelf() ); }}

GraphAwareTM

?) Precompute

GraphAwareTM

public final class FriendsComputingEngine extends Neo4jTopLevelDelegatingEngine { public FriendsComputingEngine() { super(new FriendsContextFactory()); } @Override protected List<RecommendationEngine<Node, Node>> engines() { return asList( new FriendsInCommon(), new RandomPeople() ); } @Override protected List<PostProcessor<Node, Node>> postProcessors() { return asList( new RewardSameLabels(), new RewardSameLocation(), new PenalizeAgeDifference() ); } @Override public ParticipationPolicy<Node, Node> participationPolicy(Context<Node, Node> context) { return ParticipationPolicy.IF_MORE_RESULTS_NEEDED; }}

GraphAwareTM

public final class FriendsRecommendationEngine extends Neo4jTopLevelDelegatingEngine { @Override protected List<RecommendationEngine<Node, Node>> engines() { return Arrays.<RecommendationEngine<Node, Node>>asList( new Neo4jPrecomputedEngine(), new FriendsComputingEngine() ); } @Override protected List<BlacklistBuilder<Node, Node>> blacklistBuilders() { return Arrays.asList( new ExistingRelationshipBlacklistBuilder(FRIEND_OF, BOTH) ); } @Override protected List<Filter<Node, Node>> filters() { return Arrays.<Filter<Node, Node>>asList( new ExcludeSelf() ); }}

GraphAwareTM

6) Log

GraphAwareTM

public final class FriendsRecommendationEngine extends Neo4jTopLevelDelegatingEngine { @Override protected List<RecommendationEngine<Node, Node>> engines() { return Arrays.<RecommendationEngine<Node, Node>>asList( new Neo4jPrecomputedEngine(), new FriendsComputingEngine() ); } @Override protected List<BlacklistBuilder<Node, Node>> blacklistBuilders() { return Arrays.asList( new ExistingRelationshipBlacklistBuilder(FRIEND_OF, BOTH) ); } @Override protected List<Filter<Node, Node>> filters() { return Arrays.<Filter<Node, Node>>asList( new ExcludeSelf() ); } @Override protected List<Logger<Node, Node>> loggers() { return Arrays.asList( new Slf4jRecommendationLogger<Node, Node>(), new Slf4jStatisticsLogger<Node, Node>() ); }}

GraphAwareTM

7) Test

GraphAwareTM

List<Recommendation<Node>> reco = recommendationEngine.recommend(getPersonByName(“Adam"), 2);String expected = "(Vince {total:19.338144," + "ageDifference:-5.527864," + "friendsInCommon:14.866008," + "sameGender:10.0})," + "(Luanne {total:11.553411," + "ageDifference:-3.312597," + "friendsInCommon:14.866008})"; assertEquals(expected, toString(reco));

GraphAwareTM

Trouver des “choses” à recommanderServir les recommandations les plus rélévantesMesurer la qualité des recommandationsTime to market / coût du développement

Challenges Business

GraphAwareTM

Performance (real-time!)SimplicitéFlexibilité

Challenges Techniques

GraphAwareTM

A vous !<dependencies>

...

<dependency> <groupId>com.graphaware.neo4j</groupId> <artifactId>recommendation-engine</artifactId> <version>2.2.0.30.6</version> </dependency>

...

<dependencies>

GraphAwareTM

Habilité intégrée pour pré-computer les recommandationsAutres classes intégréesTime-based ParticipationPolicy Raisons for RecommendationContribuez !https://github.com/graphaware/neo4j-reco

Il y a encore plus !

GraphAwareTM

Algorithmes intégrésIntégration avec des compute enginesMachine learning

Futur

GraphAwareTM

Le Framework GraphAware rend facile la conception, le test et le déploiement de fonctionnalités pour Neo4j, aussi bien génériques que spécifiques à un domaine.

GraphAware Framework

GraphAwareTM

GraphUnit& RestTest RelCount WarmUp Schema (wip) Recommendation

Engine

GraphAware Framework

ChangeFeed UUID TimeTree Algorithms NodeRank

GraphAwareTM

Open Source (GPL)ActifProduction ReadyGithub: github.com/graphawareWeb: graphaware.comMaven Central

GraphAware Framework

GraphAwareTM

EssayezDonnez-nous du feedbackContribuezConcevez vos propres modulesContactez-nous pour du support/consultance

GraphAware Framework

Questions ?

Merci !

GraphAwareTM

Christophe Willemsen

Twitter: @ikwattro

Github: @ikwattro