Bon, voila comment j'ai procédé, mais cela peut être adapté 
suivant les commentaires que vous pourrez faire.

Je prend un exemple pour simplifier (issu de la base de 
bueil) et assez tordu en même temps pour me permettre de 
pointer un des problèmes de la recherche par titre où il 
n'y a pas d'autorités (et ça, on n'y pourra jamais rien...)

Rappel du problème :
l'utilisateur fournit une chaîne.
la chaîne est divisée en mots.
si tous les mots ont plus de trois caractères, on utilisera 
la méthode MATCH/AGAINST (fulltext).
si les ou un des mots comprennent 3 ou moins caractères, on 
switche sur la recherche REGEXP.
Les mots vides sont éliminés de la requête utilisateur (le, 
la, les, l', typiquement.
Si l'utilisateur a saisi des caractères utilisés dans les 
masques d'expressions régulières (|$, ^ et autres), j'ai 
considéré qu'il avait saisi une expression régulière et il 
n'y a aucun traitement (je pars du principe que dans ce 
cas, il sait ce qu'il fait).
Là dessus vient se greffer la nécessité de retourner un 
indice de pertinence pour chaque résultat retourné (tri par 
ordre décroissant de pertinence + on fera une petite image 
pour visualiser l'indice de confiance du résultat).

Je prend l'exemple 'vietnam' saisi en recherche titre
Le mot fait plus de 4 caractères, donc MATCH/AGAINST : la 
requête générée par la fonction test_title_query() est :

select *,MATCH (index_tit1,index_tit2,index_tit3, 
index_tit4, index_serie) AGAINST ('vietnam') AS indice from 
notices WHERE MATCH (index_tit1,index_tit2,index_tit3, 
index_tit4, index_serie) AGAINST ('vietnam') ORDER BY MATCH 
(index_tit1,index_tit2,index_tit3, index_tit4, index_serie) 
AGAINST ('vietnam') DESC

1 résultat avec son indice de pertinence :

Ho Chi Minh 7.2678657682646

Ca colle : le sous-titre est 'de l'Indochine au Vietnam' 
donc c'est normal que ça sorte.
Cependant, je trouve ça bizarre parce que j'ai un peu 
parcouru la base de Bueil. J'ai l'impression que je devrais 
avoir plus de résultats.

Comme je suis un bibliothécaire avec de l'expérience ;-), 
je me dis : 'à 100 contre un, la BDT a saisi vietnam avec 
un tiret !!!' (les deux orthographes sont admises et la 
rêgle de catalogage dit qu'on doit saisir le titre 
exactement comme il figure sur la page de titre du livre). 
De toutes les façons, pour cet exemple, je suis sûr que les 
trois quarts des gens seraient passés par la recherche 
catégorie où c'est une autorité, donc le problème se lève. 
On aurait pu faire aussi en titre 'vietnam|viet-nam' pour 
aboutir, mais il faut connaître un peu les regexp...

Je saisis donc 'viet-nam'.

première chose que fait la fonction test_title_query() : 
virer le tiret pour diviser tout ça en mots (de toute 
façon, il est exclu de index_tit1 quand on fait le 'pseudo-
index' qui sert à la recherche).

Ca devient 'viet nam' (mot avec moins de 4 caractères : on 
switche en regexp).

La requête générée est :

select *,5*(index_serie REGEXP 'viet') + 4*(index_tit1 
REGEXP 'viet') + 3*(index_tit4 REGEXP 'viet') + 2*
(index_tit3 REGEXP 'viet') + 1*(index_tit2 REGEXP 'viet') + 
5*(index_serie REGEXP 'nam') + 4*(index_tit1 REGEXP 'nam') 
+ 3*(index_tit4 REGEXP 'nam') + 2*(index_tit3 REGEXP 'nam') 
+ 1*(index_tit2 REGEXP 'nam') AS indice from notices WHERE 
(index_serie REGEXP 'viet' OR index_tit1 REGEXP 'viet' OR 
index_tit2 REGEXP 'viet' OR index_tit3 REGEXP 'viet' OR 
index_tit4 REGEXP 'viet') AND (index_serie REGEXP 'nam' OR 
index_tit1 REGEXP 'nam' OR index_tit2 REGEXP 'nam' OR 
index_tit3 REGEXP 'nam' OR index_tit4 REGEXP 'nam') ORDER 
BY 5*(index_serie REGEXP 'viet') + 4*(index_tit1 
REGEXP 'viet') + 3*(index_tit4 REGEXP 'viet') + 2*
(index_tit3 REGEXP 'viet') + 1*(index_tit2 REGEXP 'viet') + 
5*(index_serie REGEXP 'nam') + 4*(index_tit1 REGEXP 'nam') 
+ 3*(index_tit4 REGEXP 'nam') + 2*(index_tit3 REGEXP 'nam') 
+ 1*(index_tit2 REGEXP 'nam') DESC, index_serie DESC, 
index_tit1 ASC

Joli non ? Le AND du milieu de la requête est généré 
suivant un paramètre qu'on passe à la fonction. Suivant la 
valeur, ce sera AND ou OR (bouton radio dans le form de 
recherche : tous les mots/au moins un des mots).

Ca me retourne deux résultats (avec indice de 
pertinence) :

Viêt-Nam 8
Ho Chi Minh 6

C'est mieux déjà. J'ai fixé l'indice de la façon suivante : 
si la séquence figure dans le titre de série, j'attribue un 
facteur de 5. Si elle est dans le titre propre un facteur 
de 4. sous-titre, etc...

Le tout est trié sur indice de pertinence décroissant, 
titre de série décroissant (pour avoir les séries au début) 
et titre propre ascendant (pour trier quand même si 
l'indice est identique).

résultat des courses : pour moi, ça marche (j'en suis même 
assez content car cela élimine un certain bordel en 
recherche fulltext). Le bémol est dû à la nature même de la 
recherche par titre : il faut réfléchir 
des fois. Le problème du tiret est insoluble d'ailleurs : 
comment faire comprendre au logiciel que ça peut être une 
limite de mot et parfois pas une limite de mot ?-)

Jetez y un coup d'oeil (c'est 
dans ./includes/misc.inc.php). Si c'est OK pour vous, 
j'implémente ça dans le biniou en vrai et on aura la 
recherche avec 
les opérateurs booléens !!!

J'ai encore un petit truc à résoudre : il faudrait pour 
faire la minibarre retourner aussi l'indice maximum pour la 
recherche en cours. C'est pas difficile, je m'en vais 
vérifier que la fonction MAX existe en MySQL...

A+



Selon François Lemarchand <[EMAIL PROTECTED]>:

> Je vois qu'il y a du monde même le dimanche ;-)
> 
> Je suis sur la refonte de la recherche titre. Pour 
> l'instant, je bosse sur une fonction 'test_title_query()'
> 
> dans misc.inc.php. Normalement, ça vient remplacer 
> analyze_title_query().
> 
> Ca commence comme ça (le reste est commité, mais pas 
> utilisé encore) :
> 
> function test_title_query($query, $operator=TRUE, 
> $force_regexp=FALSE)
> {
>     // fonction d'analyse d'une recherche sur titre
>     // la fonction retourne un tableau :
> 
>     $query_result = array(  'type' => 0,
>                             'restr' => '',
>                             'order' => '');
>     // $query_result['type'] = type de la requête :
>     // 0 : rien (problème) 1: match/against 2: regexp
>     // $query_result['restr'] = critères de restriction
>     // $query_result['order'] = critères de tri
> 
>     // si operator TRUE La recherche est booléenne AND
>     // si operator FALSE La recherche est booléenne OR
>     // si force_regexp: la rech. est forcée en mode
> regexp
> ...
> 
> Si je cherche 'mouvement libération femme' avec recherche
> 
> regexp forcée, j'obtiens ce restricteur :
> 
> WHERE (index_tit1 REGEXP 'mouvement' OR index_tit2 
> REGEXP 'mouvement' OR index_tit3 REGEXP 'mouvement' OR 
> index_tit4 REGEXP 'mouvement' OR index_serie 
> REGEXP 'mouvement') AND (index_tit1 REGEXP 'liberation'
> OR 
> index_tit2 REGEXP 'liberation' OR index_tit3 
> REGEXP 'liberation' OR index_tit4 REGEXP 'liberation' OR
> 
> index_serie REGEXP 'liberation') AND (index_tit1 
> REGEXP 'femme OR index_tit2 REGEXP 'femme' OR index_tit3
> 
> REGEXP 'femme' OR index_tit4 REGEXP 'femme' OR
> index_serie 
> REGEXP 'femme')
> 
> Ca me paraît OK sur la forme, mais question utilisation
> de 
> ressources ça te dit quoi ? (pas un peu lourd ?).
> 
> J'ai une autre soluce sous le coude :
> 
> WHERE index_tit1 REGEXP 'mouvement|liberation|femme' OR 
> index_tit2 
> REGEXP 'mouvement|liberation|femme' OR index_tit3 
> REGEXP 'mouvement|liberation|femme' OR 
> index_tit4 REGEXP 'mouvement|liberation|femme' OR 
> index_serie 
> REGEXP 'mouvement|liberation|femme'
> 
> qui me semble moins gourmande, mais je tiens à appliquer
> le 
> booléen fourni en param même si ça switche sur REGEXP.
> 
> Si je ne force pas la REGEXP, j'obtiens cela (beaucoup
> plus 
> civilisé...) :
> 
> WHERE MATCH (index_tit1,index_tit2,index_tit3,
> index_tit4, 
> index_serie) AGAINST ('mouvement') AND MATCH 
> (index_tit1,index_tit2,index_tit3,index_tit4,
> index_serie) 
> AGAINST ('liberation') AND MATCH 
> (index_tit1,index_tit2,index_tit3,index_tit4,
> index_serie) 
> AGAINST ('femme')
> 
> Une fois que j'ai fini le restricteur, reste le problème
> de 
> la création d'un indice de confiance pour les REGEXP.
> 
> apparemment, champ REGEXP 'montruc' me retourne 0 ou 1, 
> donc si je construit mon indice comme ça :
> 
> SELECT stuff, champ1 REGEXP 'truc' + champ2 REGEXP 'truc'
> 
> + ... AS indice
> 
> j'obtiens une approximation d'un simili indice ?
> 
> (je m'occuperais de la mise à l'echelle pour la
> mini-barre 
> sur le moment de sa génération...)
> 
> A+
> 
> -- 
> François Lemarchand
> homepage : http://balno.free.fr/
> PhpMyBibli : http://phpmybibli.sourceforge.net
> 
> Liste de diffusion phpmybibli.devel
> Pour se désinscrire :
> mailto:[EMAIL PROTECTED]
subject=unsubscribe
> 
> 


-- 
François Lemarchand
homepage : http://balno.free.fr/
PhpMyBibli : http://phpmybibli.sourceforge.net

Liste de diffusion phpmybibli.devel
Pour se désinscrire : mailto:[EMAIL PROTECTED]

Répondre à