Skip to main content

Recherche plein-texte

Les offres et les candidats sont indexés en PostgreSQL via tsvector avec configuration french. Les résultats sont triés par pertinence + date.

Pipeline d’indexation

Pondération des colonnes

WeightFacteur de rangChamps
A1.0titre
B0.4competences_requises (tableau)
C0.2secteur, type_contrat, ville, niveau_experience
D0.1description

Requête type

SELECT
  o.*,
  ts_rank_cd(o.search_vector, query, 32) AS rank
FROM offres o,
  websearch_to_tsquery('french', :q) AS query
WHERE
  o.search_vector @@ query
  AND o.status = 'PUBLISHED'
ORDER BY rank DESC, o.published_at DESC
LIMIT :size OFFSET :page * :size;

Syntaxe utilisateur (websearch_to_tsquery)

InputInterprétation
développeur javadéveloppeur & java
développeur OR python`développeurpython`
"lead developer"Phrase exacte
java -seniorjava & !senior
dev*Préfixe (avec tsquery custom)

Endpoints concernés

EndpointIndex
GET /v1/api/offres/searchoffres.search_vector
GET /v1/api/offres/autocompleteoffres.titre (trigram)
GET /v1/api/admin/candidatescandidats.search_vector
GET /v1/api/vivier/searchidem

Autocomplete

Séparé de la recherche principale — utilise pg_trgm (trigrams) pour la tolérance aux fautes.
SELECT DISTINCT titre
FROM offres
WHERE status = 'PUBLISHED'
  AND titre % :q              -- similarity > threshold
ORDER BY similarity(titre, :q) DESC, titre
LIMIT 10;

Filtres combinables

Paramètres de recherche

ParamètreTypeExemple
qstringdéveloppeur java
secteurarraySOFTWARE,FINANCE
villestringDouala
typeContratarrayCDI,CDD
niveauExperiencestringSENIOR
salaireMinint500000
dateDebutdate2026-01-01
entrepriseIdlong42
pageint0
sizeint20
sortstringrelevance,desc / published_at,desc

Limitations

  • La recherche tsvector ignore les mots vides français (stopwords). Ex. “le”, “de”, “un” ne sont jamais indexés.
  • La longueur max de q est 200 caractères.
  • websearch_to_tsquery supporte les opérateurs simples ; pour prefix* il faut passer par /autocomplete.

Rafraîchissement de l’index

L’index GIN est mis à jour en synchrone via trigger. Pas de job asynchrone nécessaire.
CREATE TRIGGER offres_search_vector_update
BEFORE INSERT OR UPDATE ON offres
FOR EACH ROW EXECUTE FUNCTION update_offres_search_vector();

Monitoring

Candidats — recherche recruteur

La recherche candidats (accessible aux recruteurs via vivier) est plus restreinte :
  • Le candidat doit avoir opté pour la visibilité publique de son profil
  • Les critères sont : compétences, niveau d’expérience, secteur, ville
  • La description libre et le CV ne sont pas indexés dans search_vector (RGPD)