Personne Films Pierre Van Gogh, Sacrifice, La guerre des étoiles Anne Van Gogh, La guerre des étoiles, Sacrifice Jacques Batman, La guerre des étoiles Phileas Batman, La guerre des étoil
Trang 1Nous ne donnons pas le code d’insertion des messages similaire à ceux déjà vus pour les films ou les internautes Vous pouvez le trouver dans le code deFilmCtrl.php En revanche, il est plus intéressant d’examiner l’affichage des messages, qui doit se faire
de manière hiérarchique, avec pour chaque message l’ensemble de ses descendants, le nombre de niveaux n’étant pas limité Comme souvent avec ce type de structure, une fonction récursive permet de résoudre le problème de manière élégante et concise
La méthode afficheMess() est chargée d’afficher, pour un film, la liste des réponses à un message dont l’identifiant est passé en paramètre Pour chacun de ces messages, on crée une ancre permettant de lui répondre, et, plus important,
on appelle à nouveau (récursivement) la fonction AfficheMess() en lui passant l’identifiant du message courant pour afficher tous ses fils La récursion s’arrête quand
on ne trouve plus de fils
Le code présente une subtilité pour la gestion de la vue Ce que l’on doit afficher ici, c’est un arbre dont chaque nœud correspond à un message et constitue la racine
du sous-arbre correspondant à l’ensemble de ses descendants Pour l’assemblage final avec le moteur de templates, on doit associer un nom d’entité à chaque nœud C’est
le rơle de la variable nom_groupe ci-dessous qui identifie de manière unique le nœud
correspondant à un message et à ses descendants par la chaỵne groupid , ó id
est l’identifiant du message La fonction affichemess() renvoie la représentation HTML du nœud courant, ce qui correspond donc à une instanciation de bas vers le haut de l’ensemble des nœuds constituant l’arborescence
p r i v a t e f u n c t i o n a f f i c h e M e s s ( $ i d _ f i l m , $ i d _ p e r e )
{
/ / R e c h e r c h e d e s m e s s a g e s f i l s du p è r e c o u r a n t
$ r e q u e t e = " SELECT ∗ FROM Message "
"WHERE i d _ f i l m = ’ $ i d _ f i l m ’ AND i d _ p e r e = ’ $ i d _ p e r e ’ " ;
/ / On c r é e u n e e n t i t é n o m _ g r o u p e p o u r p l a c e r l a p r é s e n t a t i o n / / d e s r é p o n s e s au m e s s a g e i d _ p e r e
$nom_groupe = " g r o u p e " $ i d _ p e r e ;
$ t h i s−>vue−>s e t V a r ( $nom_groupe , " " ) ;
/ / A f f i c h e d e s m e s s a g e s d a n s u n e l i s t e , a v e c a p p e l s r é c u r s i f s
$ r e s u l t a t = $ t h i s−>bd−>execRequete ( $ r e q u e t e ) ;
w h i l e ( $ m e s s a g e = $ t h i s−>bd−>o b j e t S u i v a n t ( $ r e s u l t a t ) ) { / / A p p e l r é c u r s i f p o u r o b t e n i r l a m i s e e n f o r m e d e s
/ / r é p o n s e s
$ t h i s−>vue−>r e p o n s e s = $ t h i s −>a f f i c h e M e s s ( $ i d _ f i l m ,
$ m e s s a g e−>i d ) ; / / On p l a c e l e s i n f o r m a t i o n s d a n s l a v u e
$ t h i s−>vue−>t e x t e _ m e s s a g e = $message −>t e x t e ;
$ t h i s−>vue−>i d _ p e r e = $message −>i d ;
$ t h i s−>vue−> s u j e t = $message −> s u j e t ;
/ / A t t e n t i o n à b i e n c o d e r l e t e x t e p l a c é d a n s u n e URL
$ t h i s−>vue−>s u j e t _ c o d e = ur lEnc ode ( $message −> s u j e t ) ;
$ t h i s−>vue−>e m a i l _ c r e a t e u r = $message −>e m a i l _ c r e a t e u r ;
Trang 2/ / D é c o d a g e d e l a d a t e Unix
$ i d a t e = g e t D a t e ( $ m e s s a g e−>d a t e _ c r e a t i o n ) ;
/ / M i s e e n f o r m e d e l a d a t e d é c o d
$ t h i s−>vue−>d a t e _ m e s s a g e =
$ i d a t e [ ’ mday ’ ] " / " $ i d a t e [ ’ mon ’ ] " / " $ i d a t e [ ’ y e a r ’ ] ;
$ t h i s−>vue−>heure_message = $ i d a t e [ ’ h ours ’ ] " h e u r e s "
$ i d a t e [ ’ m i n u t e s ’ ] ;
i f ( $ i d _ p e r e != 0 )
$ t h i s−>vue−>p r e f i x e = "RE : " ;
e l s e
$ t h i s−>vue−>p r e f i x e = " " ;
/ / C r é a t i o n d e l a p r é s e n t a t i o n du m e s s a g e c o u r a n t , e t
/ / c o n c a t é n a t i o n d a n s l ’ e n t i t é $ n o m _ g r o u p e
$ t h i s−>vue−>append ( $nom_groupe , " message " ) ;
}
/ / On r e n v o i e l e s m e s s a g e s du n i v e a u c o u r a n t , a v e c t o u t e s / / l e u r s r é p o n s e s
r e t u r n $ t h i s−>vue−>getVar ( $nom_groupe ) ;
}
Au moment de l’appel initial à cette fonction, on lui donne l’identifiant 0, ce qui revient à afficher au premier niveau tous les messages qui ne constituent pas des réponses Ensuite, à chaque appel à afficheMess(), on ouvre une nouvelle balise
<ul> Ces balises seront imbriquées dans le document HTML produit, qui donnera donc bien une présentation hiérarchique des messages
On peut remarquer ici le traitement des dates Elles sont stockées dans la base
sous la forme d’un « timestamp » Unix, qui se décode très facilement avec la fonction
getDate() Cette dernière renvoie un tableau (voir page 496) avec tous les éléments constituant la date et l’heure Il reste à les mettre en forme selon le format souhaité
/ / D é c o d a g e d e l a d a t e Unix
$ i d a t e = g e t D a t e ( $ m e s s a g e−>d a t e _ c r e a t i o n ) ;
/ / M i s e e n f o r m e d e l a d a t e d é c o d é e
$ d a t e _ a f f i c h e =
$ d a t e [ ’ mday ’ ] " / " $ i d a t e [ ’ mon ’ ] " / " $ i d a t e [ ’ y e a r ’ ] ;
$ h e u r e _ a f f i c h e = $ i d a t e [ ’ h o u r s ’ ] " h e u r e s " $ i d a t e [ ’ m i n u t e s ’ ] ;
7.4 RECOMMANDATIONS
Nous abordons maintenant le module de prédiction qui constitue l’aspect le plus original du site D’une manière générale, la recommandation de certains produits
en fonction des gỏts supposés d’un visiteur intéresse de nombreux domaines, dont bien entendu le commerce électronique Les résultats obtenus sont toutefois assez aléatoires, en partie parce que les informations utilisables sont souvent, en qualité comme en quantité, insuffisantes
Trang 3L’idée de base se décrit simplement Au départ, on sait que telle personne a aimé tel film, ce qui constitue la base de données dont un tout petit échantillon est donné ci-dessous
Personne Films
Pierre Van Gogh, Sacrifice, La guerre des étoiles Anne Van Gogh, La guerre des étoiles, Sacrifice Jacques Batman, La guerre des étoiles
Phileas Batman, La guerre des étoiles, Rambo Marie Sacrifice, Le septième sceau
Maintenant, sachant que Claire aime Van Gogh (le film !), que peut-on en déduire sur les autres films qu’elle peut aimer ? Tous ceux qui aiment Van Gogh aiment aussi Sacrifice, donc ce dernier film est probablement un bon choix On peut aller un peu plus loin et supposer que Le septième sceau devrait également être recommandé, puisque Pierre aime Van Gogh et Sacrifice, et que Marie aime Sacrifice et Le septième sceau.
La guerre des étoiles semble plaire à tout le monde ; c’est aussi une bonne
recom-mandation, bien qu’on ne puisse pas en apprendre grand-chose sur les gỏts spé-cifiques d’une personne Enfin, il y a trop peu d’informations sur ceux qui aiment
Rambo pour pouvoir en déduire des prédictions fiables.
Les techniques de filtrage coopératif (collaborative filtering en anglais) reposent
sur des algorithmes qui tentent de prédire les gỏts de personnes en fonctions de leurs votes (qui aime quoi), ainsi que de toutes les informations recueillies sur ces personnes (profession, âge, sexe, etc) Ces algorithmes étant potentiellement complexes, nous nous limiterons à une approche assez simple Un des intérêts de
ce type d’application est de faire appel intensivement à un aspect important de SQL,
les requêtes agrégat, que nous n’avons pas vu jusqu’à présent.
7.4.1 Algorithmes de prédiction
Il existe essentiellement deux approches pour calculer des prédictions
Approche par classification
On cherche à déterminer des groupes (ou classes) d’utilisateurs partageant les mêmes gỏts, et à rattacher l’utilisateur pour lequel on souhaite réaliser des prédictions à l’un de ces groupes De même, on regroupe les films en groupes/classes
En réorganisant par exemple le tableau précédent avec les personnes en ligne, les films en colonnes, un ’O’ dans les cellules quand la personne a aimé le film,
on peut mettre en valeur trois groupes de films (disons, « Action », « Classique », et
« Autres »), et deux groupes d’utilisateurs
Trang 4Batman Rambo Van Gogh Sacrifice Le septième sceau La guerre des étoiles
Il y a une assez forte similarité entre Jacques et Phileas, et toute personne qui
se verrait affecter à leur groupe devrait se voir proposer un des films du groupe
« Action » C’est vrai aussi, quoique à un moindre degré, entre le premier groupe
de personnes et les classiques Les informations sont plus clairsemées, et le degré de confiance que l’on peut attendre d’une prédiction est donc plus faible Enfin, en ce
qui concerne la guerre des étoiles, il ne semble pas y avoir d’affinité particulière avec
l’un ou l’autre des groupes d’utilisateurs
Les algorithmes qui suivent cette approche emploient des calculs de distance ou
de similarité assez complexes, et tiennent compte des attributs caractérisant chaque personne ou chaque film De plus la détermination des groupes est cỏteuse en temps d’exécution, même si, une fois les groupes déterminés, il est assez facile d’établir une prédiction
Approche par corrélation
L’algorithme utilisé pour notre site effectue un calcul de corrélation entre l’internaute qui demande une prédiction et ceux qui ont déjà voté La corrélation établit le degré
de proximité entre deux internautes en se basant sur leurs votes, indépendamment
de leurs attributs (âge, sexe, région, etc)
L’idée de départ est que pour prédire la note qu’un internaute a sur un film f, on
peut en première approche effectuer la moyenne des notes des autres internautes sur
f En notant par n a,f la note de a sur f, on obtient :
n a,f = 1
N
N
i=1
Cette méthode assez grossière ne tient pas compte de deux facteurs D’une part chaque internaute a une manière propre de noter les films, qui peut être plutơt
positive ou plutơt négative La note attribuée à un film par un internaute a ne devrait donc pas être considérée dans l’absolu, mais par rapport à la note moyenne m adonnée
par cet internaute Si, par exemple, a donne en moyenne une note de 3,5, alors une
note de 3 attribuée à un film exprime un jugement légèrement négatif, comparable à
une note de 2,5 pour un internaute b dont la moyenne est de 3.
D’autre part il faut tenir compte de la corrélation c a,b (ou degré de proximité)
entre deux internautes a et b pour estimer dans quelle mesure la note de b doit influer sur la prédiction concernant a On obtient finalement une formule améliorée, qui
effectue la moyenne des notes pondérée par le coefficient de corrélation :
n a,f = m a+ 1
C
N
Trang 5
C est la somme des corrélations Elle permet de normaliser le résultat Il reste
à déterminer comment calculer la corrélation entre deux utilisateurs a et b Il y a
plusieurs formules possibles Celle que nous utilisons se base sur tous les films pour
lesquels a et b ont tous les deux voté Ils sont désignés par j dans la formule ci-dessous.
c a,b=
j (n a,j − m a )(n b,j − m b)
j (n a,j − m a)2
On peut vérifier que si deux internautes ont voté exactement de la même manière,
le coefficient de corrélation obtenu est égal à 1 Si, d’un autre côté, l’un des inter-nautes vote de manière totalement « neutre », c’est-à-dire avec une note toujours égale à sa moyenne, on ne peut rien déduire et la corrélation est nulle On peut noter également que la corrélation entre deux internautes est d’autant plus pertinente que
le nombre de films qu’ils ont tous les deux notés est important
Il y a beaucoup d’améliorations possibles – et souhaitables Elles visent à résoudre (partiellement) les deux problèmes de base du filtrage coopératif : l’absence
d’infor-mation et le fait que certains films sont peu représentatifs (comme La guerre des étoiles
dans l’exemple ci-dessus)
7.4.2 Agrégation de données avec SQL
Toutes les requêtes vues jusqu’à présent pouvaient être interprétées comme une suite d’opérations effectuées ligne à ligne De même leur résultat était toujours constitué
de valeurs issues de lignes individuelles Les fonctionnalités d’agrégation de SQL permettent d’exprimer des conditions sur des groupes de lignes, et de constituer le
résultat en appliquant une fonction d’agrégation sur ce groupe L’exemple le plus simple consiste à calculer le nombre de lignes dans une table
SELECT COUNT(∗)
FROM F i l m
La fonction COUNT() compte le nombre de lignes Ici, le groupe de lignes est constitué de la table elle-même Il est bien entendu possible d’utiliser la clause WHERE pour sélectionner la partie de la table sur laquelle on applique la fonction d’agrégation
SELECT COUNT(∗)
FROM F i l m
WHERE g e n r e = ’ Western ’
AND annee > 1990
La fonction COUNT(), comme les autres fonctions d’agrégation, s’applique à tout
ou partie des attributs de la table On peut donc écrire également
SELECT COUNT( i d _ r e a l i s a t e u r )
FROM F i l m
WHERE g e n r e = ’ Western ’
AND annee > 1990