[Résolu] Pertinence. MATCH/AGAINST

Pertinence. MATCH/AGAINST [Résolu] - SQL/NoSQL - Programmation

Marsh Posté le 27-04-2010 à 12:09:39    

Bonjour à tous =).
 
Je suis actuellement sur un projet scolaire qui consiste à dév. un moteur traitant une "Recherche multicritères".
Dans ces critères figurent : Nom, auteur, éditeur, parution.. (On parle ici de Livre/CD/DVD/Revue).
 
J'ai 4 tables (une pour chaque type de document [livre, cd..]) avec une structure qui est à quelques champs près, la même pour toutes.
 
J'en viens au fait :
Ma recherche MULTICRITERES contient un critère "mots-clés"... Le gars saisit des mots-clés et on va faire la recherche sur les champs nom(titre)/auteur/description, pour chaque mot avec un %LIKE%...
 
Seulement j'aimerais faire un tri par pertinence, et j'ai vu que l'engine MyIsam gérait ça avec MATCH/AGAINST en mode FULLTEXT.
J'ai donc indexé mes champs nom,auteur,description en FULLTEXT pour chaque table (livre, cd, dvd, revue).
 
Voilà la tête de ma requête, quand la personne qui effectue la recherche ne précise pas le type de documents :
Avant de découvrir Match/Against

Code :
  1. SELECT * from (SELECT livre.id, livre.nom, livre.auteur, livre.description, livre.type_document FROM livre UNION SELECT cd.id, cd.nom, cd.auteur, cd.description, cd.type_document FROM cd UNION SELECT dvd.id, dvd.nom, dvd.auteur, dvd.description, dvd.type_document FROM dvd UNION SELECT revue.id, revue.nom, revue.auteur, revue.description, revue.type_document FROM revue) AS data WHERE (data.nom LIKE '%fourmis%' OR data.nom LIKE '%werber%' OR data.auteur LIKE '%fourmis%' OR data.auteur LIKE '%werber%' OR data.description LIKE '%fourmis%' OR data.description LIKE '%werber%');


 
Je suis obligé de chercher dans livre ET cd ET dvd ET revue, puis faire un groupe de 3 OR (3 champs, logique) pour chaque mot-clé saisi (ici, "fourmis" et "werber" ).
 
Avec Match et Against, voici à quoi c'est censé ressembler :

Code :
  1. SELECT * from (SELECT livre.id, livre.nom, livre.auteur, livre.description, livre.type_document FROM livre UNION SELECT cd.id, cd.nom, cd.auteur, cd.description, cd.type_document FROM cd UNION SELECT dvd.id, dvd.nom, dvd.auteur, dvd.description, dvd.type_document FROM dvd UNION SELECT revue.id, revue.nom, revue.auteur, revue.description, revue.type_document FROM revue) AS data WHERE MATCH(data.nom, data.auteur, data.description) AGAINST('fourmis lune rouge');


 
Et en plus j'ai un tri par pertinence (le + d'occurences en premier), la classe.
Seulement voilà :
ERROR 1191 (HY000) : Can't find FULLTEXT index matching the column list.
 
Quand je fais quelque chose comme

Code :
  1. SELECT * from livre WHERE MATCH(livre.nom, livre.auteur, livre.description) AGAINST('fourmis werber');


Il n'y a pas de soucis.
 
Je pense que MySQL cherche à fouiner dans "data.nom" alors que ce n'est que l'assemblage du champ Nom de mes 4 tables, et donc dit que "data.nom" n'est pas indexé en FULLTEXT (normal 'data' est un alias et non une table...).
 
J'ai bien essayé le "IN BOOLEAN MODE" dans Against, qui permet de faire ça sans FULLTEXT, mais ici la pertinence n'est plus :/.
 
Désolé pour le pavé j'ai essayé de détailler un maximum...
Merci d'avance.
 
Amicalement,
Vincent.
 
EDIT solution trouvée ^^

Code :
  1. SELECT * FROM
  2. (SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM livre WHERE MATCH(nom, auteur, description)AGAINST('astronomie soleil étoile')
  3. UNION
  4. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM dvd WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  5. UNION
  6. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM cd WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  7. UNION
  8. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM revue WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  9. ) a ORDER BY score DESC;


 
Merci à flo850 pour son aide =) !


Message édité par VinceA le 27-04-2010 à 15:12:38
Reply

Marsh Posté le 27-04-2010 à 12:09:39   

Reply

Marsh Posté le 27-04-2010 à 12:15:28    

est ce que tu ne devrai pas plutot faire  

Code :
  1. SELECT livre.id, livre.nom, livre.auteur, livre.description, livre.type_document, MATCH(DATA.nom, DATA.auteur, DATA.description) AGAINST('fourmis lune rouge') AS score  FROM livre WHERE MATCH(livre.nom, livre.auteur, livre.description) AGAINST('fourmis lune rouge')
  2.  
  3. UNION
  4. SELECT dvd.id, dvd.nom, dvd.auteur, dvd.description, dvd.type_document, MATCH(dvd.nom, dvd.auteur, dvd.description) AGAINST('fourmis lune rouge') AS score  FROM dvdWHERE MATCH(dvd.nom, dvd.auteur, dvd.description) AGAINST('fourmis lune rouge')


Reply

Marsh Posté le 27-04-2010 à 12:28:04    

@flo850 : Oh oui ! Trop con, pourquoi j'y ai pas pensé lol... ça a l'air de marcher, je vous tiens au jus !
 
Si quelqu'un a une opti pour que ça soit "moins long" je suis preneur ;).
 
En attendant merci beaucoup flo ^^

Reply

Marsh Posté le 27-04-2010 à 13:37:57    

En moins long, tu peux esasyer de factoriser tes tables  
article(id,nom,id_auteur,description,type)
avec type qui est une enum de dvd,livre,revue

Reply

Marsh Posté le 27-04-2010 à 14:24:14    

Nio ? Je connaissais pas cette méthode... J'vais devoir refaire un p'tit tour de leçon sur le site de MySQL moi (ou alors je comprends mal ce que tu veux dire ^^).
 
En tout cas ça a l'air de marcher, merci énormément =).

Reply

Marsh Posté le 27-04-2010 à 14:28:32    

tu as trois tables avec sensiblement les mêmes champs
 
pourquoi ne pas faire une seule table ?

Reply

Marsh Posté le 27-04-2010 à 14:55:29    

Parce que certaines comme CD ou DVD ont des champs spéciaux genre "nbdisque", "nbpiste".. Puis c'est un projet scolaire donc faut éviter les bricolages à la "tous ces champs à NULL si jamais c'est pas un cd ou un dvd"...
 
D'ailleurs j'constate un soucis avec la méthode SELECT UNION SELECT ... C'est qu'il fait la pertinence SELECT par SELECT, et pas sur l'ensemble des tables... :S... T'as une solution ? :P  
 
Merci

Reply

Marsh Posté le 27-04-2010 à 15:08:21    

EDIT :
 
C'est bon en fait !! :D

Code :
  1. SELECT * FROM
  2. (SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM livre WHERE MATCH(nom, auteur, description)AGAINST('astronomie soleil étoile')
  3. UNION
  4. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM dvd WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  5. UNION
  6. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM cd WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  7. UNION
  8. SELECT nom, auteur, description, MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile') AS score FROM revue WHERE MATCH(nom, auteur, description) AGAINST('astronomie soleil étoile')
  9. ) a ORDER BY score DESC;


Merci beaucoup l'ami ^^


Message édité par VinceA le 27-04-2010 à 15:13:26
Reply

Marsh Posté le 27-04-2010 à 16:02:07    

VinceA a écrit :

Parce que certaines comme CD ou DVD ont des champs spéciaux genre "nbdisque", "nbpiste".. Puis c'est un projet scolaire donc faut éviter les bricolages à la "tous ces champs à NULL si jamais c'est pas un cd ou un dvd"...
[...]
 
Merci


 
Tu fais une table "objet" qui contient les attributs communs, dont un qui sera l'enum définissant le type (cd, dvd, livre...) et une table attributs spécifiques dont le contenu va ressembler à ça :
ID
Nom attribut
Valeur attribut
Type attribut (entier, float, champ text, blob...)
 
Entre les 2 tables, y'a une relation N-N. Regardes Mantis ou Magento comme softs GPL qui implémente cette possibilité de rajouter des attributs à des objets...
 
Par contre, ça complexifie les requêtes SQL mais ça rend ton modèle très générique ;)


Message édité par rufo le 27-04-2010 à 16:02:41

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 27-04-2010 à 16:48:22    

C'est une bonne idée en effet !
 
Par contre j'ai une colle... Pourquoi un mysql_query() retourne moins de résultat que la requête directement balancée dans MySQL Server (sous console) xD ?
 
C'est un problème "annexe", je m'en chargerais plus tard ^^.
 
Je vais voir pour finir un premier jet de mon projet puis apporter ces modifications de structure à mes tables ! :)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed