Les termes saisis dans des champs d’objets indexés (fonctionnalité de recherche globale/fulltext) qui contiennent le caractère ‘-’ (hyphen/dash/trait-d’union) sont actuellement reportés tel quels dans l’index fulltext. Ces termes ne peuvent pas être retrouvé par la fonction de recherche globale sauf si l’on spécifie une recherche exacte/complète en encadrant le terme recherche entre des double quotes. Il est de ce fait impossible de rechercher une partie de ces termes avec l’opérateur * (“A-B-C123” fonctionnera, A-B-C123 ne fonctionnera pas, “A-B-C*” ne fonctionnera pas, A-B-C* ne fonctionnera pas).
Afin de contourner ce problème, nous explorons une des solutions proposées qui consiste à “hacker” l’index fulltext en réinjectant dans l’index les termes avec des ‘-’ sans les ‘-’ → l’index fulltext de A-B-C123 contiendrait “… a-b-c123 abc123…” puis de retraiter les clauses de recherches dans l’index fulltext en supprimant les ‘-’ dans les termes recherchés (le hook preSearchInex supprime dans la liste des termes recherchés tout ‘-’ non précédé d’un espace → ne touche pas aux termes -xxx pour conserver le bénéfice de l’opérateur ‘-’ mais seulement aux termes x-x-x). Ainsi, un utilisateur peut rechercher le terme A-B-C* qui sera retraité avant la recherche en ABC* et ça devrait bien trouver ce que ça doit.
Cependant, pour pouvoir mettre en œuvre complètement la solution, il faudrait pouvoir retraiter les ‘-’ non précédés d’un espace lors de la constitution de l’index fulltext…
→ Existe-til un moyen de surcharger le comportement du socle pour obtenir ce résultat ? (un hook du type getUserKeyLabel mais appliqué lors du calcul de l’index fulltext nous permettrait d’activer ce comportement particulier de manière ciblée).
→ Est-il envisageable que ce comportement soit obtenu “en standard” ?
Il faudrait tester une requête du style : A"-"B"-"C* ou "A-B-C"*
C’est fait mais malheureusement ça ne le fait pas…
Pour trouver une solution rapide et la moins crade possible, on a finalement opté pour l’ajout d’un attribut additionnel invisible (patchIndex) qui sera ajouté dans les objets concernés par le pb et un code partagé qui boucle sur une shortlist d’attributs d’objet configurés pour l’indexation et qui concaténera en preValidate les valeurs sans les ‘-’ (ça ajoutera un peu de volume BD et d’IO au runtime mais, bien que ça ne soit pas parfait (euphémisme), les résultats de recherches de type A-B-C* seront à peu près servis).
Ok ca reste un contournement.
Il faudrait voir comme escaper ces caractères spéciaux proprement (sans passer par Simplicité pour trouver la bonne syntaxe). En soit que le - et le + sans espace devant soit considéré comme un opérateur est une anomalie soit de MySQL soit de Simplicité qui formatte mal la requête.
Il est aussi possible d’explorer le mode de recherche. Simplicité utilise la recherche booléenne pur MySQL, peut-etre que la recherche “naturelle” vous conviendrait mieux.
MATCH (idx_ukey, idx_all) AGAINST ('A-B-C*' IN BOOLEAN MODE)
vs MATCH (idx_ukey, idx_all) AGAINST ('A-B-C*' IN NATURAL LANGUAGE MODE)
Ca ne permet plus de faire des AND + et NOT -
mais j’imagine que ça continue de chercher par proximité non-case-sensitive.
Le MODE serait simple à rendre paramétrable pour MySQL.
Le NATURAL LANGUAGE MODE a certainement un intérêt pour divers cas d’usage mais dans notre cas, le BOOLEAN MODE est préférable car il permet de plus facilement maîtriser ce qu’on veut trouver ou pas de manière ~relativement~ simple.
La cause racine du problème me semble également plutôt dans MySQL que dans Simplicité car il n’y a a priori aucun moyen d’escaper le ‘-’… du coup je l’ai extrait en amont à défaut de pouvoir faire mieux.
Le contournement appliqué dans notre contexte spécifique MySQL est pour l’instant déployé et fonctionnel tel que avec ses avantages et ses défauts.
J’ai commencé à tester les modalités de recherches fulltext offertes par PostGreSQL (qui est la brique SGBD déployée en standard dans nos architectures) et il y a là aussi des subtilités que je commence à fouiller (source : PostgreSQL: Documentation: 15: 12.3. Controlling Text Search).
En particulier, je vois dans la documentation et en testant que l’opérateur ‘-’ n’est pas supporté/interprété par la couche tsquery mais que la fonction websearch_to_tsquery le supporte (de manière simplifiée telle que je le comprends, en substituant ‘-’ par ‘!’).
En testant, j’ai l’impression que la recherche globale Simplicité traite correctement la négation de terme avec ‘!’ mais ignore l’opérateur ‘-’. Ce qui semble indiquer que de manière sous-jacente le runtime “pousse” les termes saisis par l’utilisateur en tant que tsquery et n’exploite pas le service proposé de traduction websearch_to_tsquery… Pour autant, si je saisi des termes en mode tsquery ça ne ramène plus rien…
+service +nissan +dacia -etude ramène ce qui est indexé avec service, nissan et dacia mais ramène aussi les études (le ‘-’ est ignoré)
+service +nissan +dacia !etude ramène ce qui est indexé avec service, nissan et dacia mais pas les études (ce qui est attendu)
'service' & 'nissan' & 'dacia' & !'etude' (search en mode tsquery natif) ne ramène rien
J’ai donc l’impression que nous sommes entre les deux modes websearch (très simple et accessible) et tsquery (très puissant et formel).
→ Simplicité fait-il quelque-chose sur les termes avant de les pousser à PostGreSQL ?
Autre différence de comportement, avec PostGreSQL, il semble que l’opérateur ‘*’ ne soit pas nécessaire pour étendre les termes (gloss* pour couvrir gloss, glossary, glossaire, etc…). Le fait de mettre ‘*’ ou pas est traité de manière apparemment identique.
Sur PGSQL, Simplicité fait des to_tsquery assez basiquement :
remplace juste les mots and par &, et or par |
et ajoute :* à chaque terme pour une recherche qui “commence par”
Les caractères ', !, + et - ne sont pas traités, du coup j’imagine que !'etude' devient !'etude':* et ça fait n’importe quoi.
Comme tu dis, il faudrait surement utiliser websearch_to_tsquery qui est plus user friendly = utilise le parser “malin” de PGSQL ajouté en v11 surement pour cette raison.
Si j’ai bien compris, l’esprit de ce qui est actuellement implémenté consiste justement à présenter une “interface” simple/intuitive/robuste à l’utilisateur pour éviter de tomber dans les pièges d’un formalisme trop compliqué à maitriser…
Du coup, ce serait compliqué d’ajouter un pre-parsing websearch à la place du code actuel ?
Du point de vue de ma lorgnette (forcément limité), ça me semble mieux de rester cohérent avec la notice de PostGreSQL qui met en avant l’usage de l’opérateur ‘-’ (intuitif) via le formalisme websearch en amont de tsquery.