La différence entre les deux requêtes qui précèdent est subtile : COUNTexpr compte en fait le nombre de lignes telles que la valeur de expr n’est pas à NULL.. Il n’est pas possible, sauf
Trang 1La différence entre les deux requêtes qui précèdent est subtile : COUNT(expr )
compte en fait le nombre de lignes telles que la valeur de expr n’est pas à NULL.
Si on utilise ’*’, comme dans le premier cas, on est sûr de compter toutes les lignes puisqu’il y a toujours au moins un attribut qui n’est pas à NULL dans une ligne (par exemple l’attribut titre est déclaré à NOT NULL : voir chapitre 4) En revanche la deuxième requête ne comptera pas les lignes ó id_realisateur est à NULL.
Il n’est pas possible, sauf avec la clause GROUP BY qui est présentée plus loin, d’uti-liser simultanément des noms d’attributs et des fonctions d’agrégation La requête suivante est donc incorrecte :
SELECT t i t r e , 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
On demande en fait alors à MySQL deux choses contradictoires D’une part il faut afficher tous les titres des westerns parus après 1990, d’autre part donner le nombre des réalisateurs de ces westerns Il n’y a pas de représentation possible de cette information sous forme d’une table avec des lignes, des colonnes, et une seule valeur par cellule, et SQL, qui ne sait produire que des tables, rejette cette requête.
La liste des fonctions d’agrégation est donnée dans la table 7.1.
Tableau 7.1 — Les fonctions d’agrégation de MySQL
COUNT ( expression) Compte le nombre de lignes.
AVG( expression) Calcule la moyenne deexpression.
MIN( expression) Calcule la valeur minimale deexpression.
MAX ( expression) Calcule la valeur maximale deexpression.
SUM( expression) Calcule la somme deexpression.
STD( expression) Calcule l’écart-type deexpression.
Les requêtes dont nous avons besoin pour nos prédictions calculent des moyennes.
La moyenne des notes pour l’internaute fogg@foo.fr est obtenue par :
SELECT AVG( n o t e )
FROM N o t a t i o n
WHERE e m a i l = ’ f o g g @ f o o f r ’
Symétriquement, la moyenne des notes pour un film –par exemple, Vertigo– est
obtenue par :
SELECT AVG( n o t e )
FROM N o t a t i o n
WHERE t i t r e = ’ V e r t i g o ’
Trang 2La clause GROUP BY
Dans les requêtes précédentes, on applique la fonction d’agrégation à l’ensemble du résultat d’une requête (donc potentiellement à l’ensemble de la table elle-même).
Une fonctionnalité complémentaire consiste à partitionner ce résultat en groupes,
pour appliquer la ou les fonction(s) d’agrégat à chaque groupe On construit les groupes en associant les lignes partageant la même valeur pour un ou plusieurs attributs.
La requête suivante affiche les internautes avec leur note moyenne :
SELECT e m a i l , AVG( n o t e )
FROM N o t a t i o n
GROUP BY e m a i l
On constitue ici un groupe pour chaque internaute (clause GROUP BY email) Puis on affiche ce groupe sous la forme d’une ligne, dans laquelle les attributs peuvent être de deux types :
1 ceux dont la valeur est constante pour l’ensemble du groupe, soit précisément les attributs du GROUP BY, ici l’attribut email ;
2 le résultat d’une fonction d’agrégation appliquée au groupe : ici AVG(note) Bien entendu, il est possible d’exprimer des ordres SQL comprenant une clause WHERE et d’appliquer un GROUP BY au résultat D’autre part, il n’est pas nécessaire de faire figurer tous les attributs du GROUP BY dans la clause SELECT Enfin, le AS permet
de donner un nom aux attributs résultant d’une agrégation.
Voici un exemple assez complet donnant la liste des films avec le nom et le prénom de leur metteur en scène, et la moyenne des notes obtenues, la note minimale
et la note maximale.
SELECT f t i t r e , nom , prenom , AVG( n o t e ) AS moyenne ,
MIN( n o t e ) AS noteMin , MAX( n o t e ) AS noteMax FROM F i l m AS f , N o t a t i o n AS n , A r t i s t e AS a
WHERE f t i t r e = n t i t r e
AND f i d _ r e a l i s a t e u r = a i d
GROUP BY f t i t r e , nom , prenom
L’interprétation est la suivante : (1) on exécute d’abord la requête SELECT FROM WHERE, puis (2) on prend le résultat et on le partitionne, enfin (3) on calcule le résultat des fonctions pour chaque groupe.
7.4.3 Recommandations de films
Deux méthodes de recommandations sont proposées, toutes deux implantées dans le contrôleur Recomm L’internaute peut choisir le nombre de films à afficher (10 par défaut) et appuyer sur un des boutons correspondant aux deux choix proposés (voir figure 7.5) L’action proposer associée au formulaire effectue quelques tests initiaux pour vérifier qu’un calcul de proposition est bien possible, et se contente d’appeler
la fonction appropriée L’affichage des films, standard, n’est pas montré dans le code ci-dessous Il figure bien sûr dans les fichiers du site.
Trang 3Figure 7.5 — Formulaire d’accès aux prédictions
f u n c t i o n p r o p o s e r ( )
{
/ / D ’ a b o r d on r é c u p è r e l e s c h o i x d e l ’ u t i l i s a t e u r
/ / I l f a u d r a i t v é r i f i e r qu ’ i l s e x i s t e n t b i e n
$ n b _ f i l m s = $_POST [ ’ n b _ f i l m s ’ ] ;
$ l i s t e _ t r i e e = i s S e t ( $_POST [ ’ f i l m s _ t r i e s ’ ] ) ;
i f ( $ n b _ f i l m s <= 0 o r $ n b _ f i l m s > 3 0 ) {
$ t h i s−>vue−>contenu =
" Ce s c r i p t a t t e n d une v a r i a b l e n b _ f i l m s c o m p r i s e e n t r e 1
e t 30\n " ; }
e l s e {
/ / On v é r i f i e q u e l ’ i n t e r n a u t e a n o t é s u f f i s a m m e n t d e f i l m s
$ n b _ n o t e s = U t i l : : NombreNotes ( $ t h i s−>s e s s i o n −>email , $ t h i s
−>bd ) ; / / M e s s a g e d ’ a v e r t i s s e m e n t s ’ i l n ’ y a p a s a s s e z d e f i l m s
i f ( $ n b _ n o t e s < s e l f : : MIN_NOTES and ! $ l i s t e _ t r i e e ) {
$ t h i s−>vue−>a v e r t i s s e m e n t =
" Vous n ’ a v e z p a s n o t é a s s e z de f i l m s ( $ n b _ n o t e s ) " " p o u r que n o u s p u i s s i o n s é t a b l i r une p r é d i c t i o n !\ n " ;
$ l i s t e _ t r i e e = t r u e ;
}
e l s e {
$ t h i s−>vue−>a v e r t i s s e m e n t = " " ;
}
$ t h i s−>vue−>nb_notes = $nb_notes ;
/ / C a l c u l d e l a l i s t e d e s m e i l l e u r s f i l m s
Trang 4i f ( $ l i s t e _ t r i e e ) {
$ f i l m s = $ t h i s−> l i s t e T r i e e ( $ n b _ f i l m s ) ;
$ t h i s−>vue−>n b _ f i l m s = $ n b _ f i l m s ;
$ t h i s−>vue−> s e t F i l e ( " contenu " , " r e c o m m _ l i s t e _ t r i e e t p l " ) ;
}
e l s e {
/ / C a l c u l d e s p r é d i c t i o n s
$ t h i s−>vue−>ma_moyenne =
U t i l : : m o y e n n e I n t e r n a u t e ( $ t h i s−>s e s s i o n −>email , $ t h i s
−>bd ) ;
$ f i l m s = $ t h i s−>p r e d i c t i o n ( $ t h i s −>s e s s i o n −>email ,
$ n b _ f i l m s , $ t h i s−>bd ) ;
$ t h i s−>vue−> s e t F i l e ( " contenu " , " r e c o m m _ l i s t e _ p r e d i t e t p l " ) ;
}
/ / E n s u i t e on a f f i c h e l a l i s t e d e s f i l m s −− V o i r l e c o d e
}
Les deux méthodes listeTriee() et prediction() correspondent respective-ment aux deux types de propositions possibles Elles sont toutes deux implantées comme des méthodes privées du contrôleur Recomm et données plus bas.
Liste des films les plus populaires
La méthode listeTriee() s’appuie sur les fonctionnalités d’agrégation de SQL pour construire la liste des films avec leur note moyenne Le résultat est placé dans
un tableau associatif, la clé étant l’identifiant du film et la valeur la note moyenne pour ce film.
Il ne reste plus qu’à trier sur la note, en ordre décroissant et à afficher les 10, 20
ou 30 premiers films de la liste triée PHP fournit de nombreuses fonctions de tri
de tableau (voir annexe C), dont asort() et arsort() pour trier sur les valeurs,
et ksort() ou krsort() pour trier sur les clés un tableau associatif, respective-ment en ordre croissant et en ordre décroissant C’est arsort() qui nous intéresse ici.
Finalement, on affiche la liste des films (voir figure 7.6), en associant le titre à une ancre menant au contrôleur Film pour la présentation détaillée et le forum de discussion.
p r i v a t e f u n c t i o n l i s t e T r i e e ( $ n b F i l m s )
{
$ f i l m s = a r r a y ( ) ;
/ / R e c h e r c h e d e s f i l m s e t d e l e u r n o t e m o y e n n e
$ c l a s s e m e n t = " SELECT i d _ f i l m , AVG( n o t e ) AS n o t e
" " FROM N o t a t i o n GROUP BY i d _ f i l m " ;
$ r e s u l t a t = $ t h i s−>bd−>execRequete ( $ c l a s s e m e n t ) ;
Trang 5/ / On c r é e un t a b l e a u a s s o c i a t i f d e s f i l m s , a v e c l e u r n o t e / / m o y e n n e
$ i = 1 ;
w h i l e ( $ f i l m = $ 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 ) ) {
$ f i l m s [ $ f i l m−>i d _ f i l m ] = $film −>note ;
i f ( $ i ++ >= $ n b F i l m s ) b r e a k ;
}
/ / T r i du t a b l e a u p a r o r d r e d é c r o i s s a n t s u r n o t e m o y e n n e
a r s o r t ( $ f i l m s ) ;
r e t u r n $ f i l m s ;
}
Figure 7.6 — Liste des films les plus appréciés
Calcul des prédictions
Le calcul des prédictions est nettement plus complexe que le tri des films sur leur note moyenne La méthode prediction() fait elle-même appel à quelques autres fonctions implantées comme des méthodes statiques de la classe Util.
1 MoyenneInternaute(email ) calcule la note moyenne de l’internaute identifié par email.
2 ChercheNotation(email, id_film ), déjà rencontrée, recherche la notation
d’un internaute sur un film.
3 CalculCorrelation(email1, email2 ), calcule le coefficient de corrélation
entre deux internautes.
4 CalculPrediction(email, id_film, tableauCorrelation ), prédit la note
d’un film pour un internaute, étant donné le tableau des corrélations entre cet internaute et tous les autres.
Nous ne donnerons pas les deux premières fonctions ci-dessus qui se contentent d’exécuter une requête SQL (une agrégation pour MoyenneInternaute()) et