Aller au contenu

Pourquoi une recherche SQL (unaccent) plutôt que Typesense

La recherche d'articles de l'espace utilisateur (le champ imposant de l'accueil, voir Rechercher un article dans son espace) est servie par une simple requête PostgreSQL, alors même que Typesense fait partie de la stack de Kirexo. Cette page explique pourquoi ce choix, et à quelles conditions Typesense reprendrait la main.

Le besoin réel est étroit

La recherche §6 de l'espace couvre un périmètre volontairement limité :

  • elle porte sur le titre uniquement des articles, jamais sur leur corps ;
  • elle est scopée à l'utilisateur courant — chacun ne fouille que ses propres articles, dont le volume par compte reste modeste ;
  • la seule exigence de confort est d'être insensible aux accents et à la casse (« ecole » doit trouver « École »).

Il n'y a ni recherche plein-texte, ni pertinence à pondérer, ni facettes, ni multi-champs. C'est un filtre exact sur une colonne, appliqué à un petit ensemble de lignes.

Ce que PostgreSQL fait suffire

Ce besoin est couvert par une seule expression, dans ArticleRepository::searchByTitleForUser() :

  • l'extension PostgreSQL unaccent (activée par migration, CREATE EXTENSION IF NOT EXISTS unaccent) replie les diacritiques ;
  • la fonction DQL utilisateur UNACCENT (src/Doctrine/DQL/UnaccentFunction.php, enregistrée dans config/packages/doctrine.yaml) l'expose au QueryBuilder ;
  • le filtre LOWER(UNACCENT(a.title)) LIKE LOWER(UNACCENT(:term)) appliqué des deux côtés rend la comparaison insensible à la fois à la casse et aux accents, sans avoir besoin d'ILIKE (non supporté en DQL) ;
  • le scope auteur (a.author = :author) et l'exclusion de la corbeille (a.status != Trashed) restreignent l'ensemble parcouru.

Le surlignage des occurrences, lui, est calculé côté serveur dans src/Twig/SearchHighlightRuntime.php avec le même repli accents/casse, puis échappé segment par segment — ce n'est pas le rôle du moteur de recherche.

Ce que Typesense aurait coûté ici

Brancher Typesense pour ce seul besoin imposerait :

  • une indexation externe à maintenir : indexer chaque article à la création, à la modification, au passage en corbeille et à la restauration ;
  • une synchronisation entre la base et l'index, avec les incohérences temporaires qu'elle introduit ;
  • une dépendance de plus dans le chemin d'une fonctionnalité aussi simple qu'un filtre de titre.

Pour un filtre exact sur une colonne, scopé à un utilisateur et portant sur un faible volume, ce coût n'est pas justifié : la base fait déjà le travail, sans état supplémentaire à réconcilier.

Quand Typesense reprendra la main

Typesense reste le bon outil dès qu'une vraie recherche plein-texte sera spécifiée : recherche dans le corps des articles, sur plusieurs champs (titre + corps + tags), avec pertinence, facettes ou tolérance aux fautes de frappe. Ce sont exactement les cas où un LIKE SQL s'effondre et où un moteur dédié devient pertinent. Tant que ce besoin n'est pas exprimé, le maintenir pour la recherche de titre serait de la complexité sans contrepartie.

Voir aussi