J'ai récemment travaillé à étendre et à adapter le module de recherche (search) de Drupal, et j'ai pensé en profiter pour montrer à quel point il est facile de modifier le comportement d'indexation de ce module.
L'un des problèmes qu'on m'a demandé de régler concerne le comportement par défaut du module de recherche à l'égard des mots composés avec un trait d'union. On pourrait raisonnablement s'attendre à ce qu'une recherche sur « intuitive » ou « counter » trouve un billet contenant le mot composé « counter-intuitive ». Pourtant, par défaut, le module de recherche ne renvoie aucun résultat à moins que vous tapiez « counter-intuitive » ou « counterintuitive ».
En lisant le code du module de recherche, on constate que les points, traits de soulignement et traits d'union intégrés aux mots sont simplement supprimés, afin de permettre une recherche pertinente pour les adresses URL et les acronymes.
Soit : nous voulons qu'une recherche sur « F.B.I. » trouve les documents contenant « FBI », et vice-versa. Mais il est contre-intuitif qu'une recherche sur les éléments d'un mot composé ne trouve pas forcément les billets contenant ce mot.
Corriger cela semblait exiger beaucoup de travail. J'ai été heureux de découvrir que l'architecture du module de recherche me permettait d'obtenir le comportement voulu pour les traits d'union, sans briser l'agréable comportement par défaut pour des choses comme les acronymes, avec une demi-douzaine de lignes de code.
La clé pour y arriver est la fonction search_preprocess(), qui invoque le hook hook_search_preprocess() dans tous les modules qui l'implémentent. Le hook reçoit une chaîne (au départ, le texte à indexer) et renvoie une version transformée de ce texte. Heureusement, ce hook est invoqué avant que les traits d'union et autres caractères du genre soient supprimés. On peut imaginer de nombreuses applications de ce type de transformation, mais on voit facilement qu'on peut s'en servir pour ajouter au texte les mots individuels qui composent un mot composé avec trait d'union.
Sans plus tarder, voici une implémentation de hook_search_preprocess(). La placer dans un module personnalisé d'une application Drupal (par exemple, example.module) donne le comportement voulu. Notez que les mots originaux du texte sont conservés, mais que les nouveaux mots obtenus en séparant les mots composés y sont ajoutés.
/**
* Implementation of hook_search_preprocess. Returns a string derived
* from the original text by splitting all hyphenated strings at the
* hyphen and appending these to the set of words of the original text.
*
* This preserves the original hypenated version of words.
*
* This uses PHP 'explode' to split the strings, hence may create
* differnent splittings of text than Drupal's core indexing mechanism.
* However, the set of words to be indexed is never diminished.
*
*/
function example_search_preprocess(&$text) {
$arr = split(' ', $text);
$newarr = $arr;
foreach ($arr as $word) {
$words = split('-', $word);
if (count($words) > 1) {
$newarr = array_merge($arr, $words);
}
}
$text = implode(' ', $newarr);
return $text;
}
On pourrait aussi utiliser hook_search_preprocess() pour ajouter des mots-clés associés qui correspondraient à un texte donné. Par exemple, on pourrait tenir un dictionnaire de mots qui ont des sens différents en anglais britannique et en anglais américain : trainer et sneaker, jumper et sweater, etc. En trouvant l'un dans un texte, on y inclurait aussi l'autre. Un autre exemple serait d'inclure des mots grammaticalement apparentés : search, searching, searched, seek, seeing, sought, etc.