🔝 Retour au Sommaire
Imaginez que vous construisez une plateforme internationale qui doit supporter la recherche en français, anglais, espagnol et arabe simultanément. Ou que vous devez personnaliser le comportement de la recherche pour votre domaine spécifique (médical, juridique, technique).
Les dictionnaires et les configurations linguistiques de PostgreSQL vous permettent de :
- Gérer correctement le stemming (réduction des mots) dans différentes langues
- Définir des stop words (mots vides) personnalisés
- Créer des synonymes et des thésaurus
- Supporter le multilinguisme dans une même application
- Adapter le traitement du texte à votre domaine métier
Sans configuration linguistique :
-- Recherche sans stemming français
SELECT to_tsvector('simple', 'Les bases de données sont essentielles');
-- Résultat : 'bases':2 'de':3 'données':4 'essentielles':6 'les':1 'sont':5
-- Problème : "Les", "de", "sont" ne sont pas filtrésAvec configuration française :
-- Recherche avec stemming français
SELECT to_tsvector('french', 'Les bases de données sont essentielles');
-- Résultat : 'base':2 'donn':4 'essenti':6
-- Stop words supprimés, stemming appliquéLe traitement d'un texte en Full-Text Search suit ce pipeline :
Texte original
↓
[1. PARSER] → Découpage en tokens (mots, nombres, ponctuation)
↓
[2. DICTIONNAIRES] → Normalisation, stemming, filtrage
↓
[3. TSVECTOR] → Représentation finale indexable
Le parser découpe le texte en tokens (unités lexicales).
-- Voir les tokens produits par le parser
SELECT * FROM ts_token_type('default');Résultat :
tokid | alias | description
------+------------+---------------------------
1 | asciiword | Word, all ASCII
2 | word | Word, all letters
3 | numword | Word, letters and digits
4 | email | Email address
5 | url | URL
6 | host | Host
7 | sfloat | Scientific notation
8 | version | Version number
12 | blank | Space symbols
23 | tag | XML tag
Exemple de parsing :
SELECT * FROM ts_parse('default', 'PostgreSQL 16.2 est disponible sur postgresql.org');Résultat :
tokid | token
------+-------------
1 | PostgreSQL
12 |
8 | 16.2
12 |
1 | est
12 |
1 | disponible
12 |
1 | sur
12 |
6 | postgresql.org
Les dictionnaires transforment les tokens en lexèmes (formes normalisées).
Types de dictionnaires :
- Stop words : Filtre les mots vides
- Stemming : Réduit les mots à leur racine
- Synonym : Remplace par des synonymes
- Thesaurus : Gestion avancée des synonymes
- Ispell : Dictionnaires morphologiques
- Snowball : Algorithmes de stemming
La configuration lie les types de tokens aux dictionnaires appropriés.
-- Voir les configurations disponibles
SELECT cfgname FROM pg_ts_config;
-- Résultat : simple, danish, dutch, english, finnish, french, german, etc.PostgreSQL offre 20+ configurations linguistiques prêtes à l'emploi :
-- Lister toutes les configurations avec détails
SELECT
cfgname AS nom,
cfgnamespace::regnamespace AS schema,
(SELECT COUNT(*) FROM pg_ts_config_map WHERE mapcfg = c.oid) AS nombre_mappings
FROM pg_ts_config c
ORDER BY cfgname; Principales configurations :
| Configuration | Langue | Stemmer | Stop Words |
|---|---|---|---|
simple |
Aucune | ❌ Non | ❌ Non |
english |
Anglais | ✅ Snowball | ✅ Oui |
french |
Français | ✅ Snowball | ✅ Oui |
spanish |
Espagnol | ✅ Snowball | ✅ Oui |
german |
Allemand | ✅ Snowball | ✅ Oui |
italian |
Italien | ✅ Snowball | ✅ Oui |
portuguese |
Portugais | ✅ Snowball | ✅ Oui |
russian |
Russe | ✅ Snowball | ✅ Oui |
arabic |
Arabe | ✅ Oui | ✅ Oui |
danish |
Danois | ✅ Snowball | ✅ Oui |
dutch |
Néerlandais | ✅ Snowball | ✅ Oui |
finnish |
Finnois | ✅ Snowball | ✅ Oui |
hungarian |
Hongrois | ✅ Snowball | ✅ Oui |
norwegian |
Norvégien | ✅ Snowball | ✅ Oui |
romanian |
Roumain | ✅ Snowball | ✅ Oui |
swedish |
Suédois | ✅ Snowball | ✅ Oui |
turkish |
Turc | ✅ Snowball | ✅ Oui |
-- Comparer le traitement d'un même texte dans différentes langues
SELECT
'simple' AS config,
to_tsvector('simple', 'running runs runner') AS result
UNION ALL
SELECT
'english',
to_tsvector('english', 'running runs runner')
UNION ALL
SELECT
'french',
to_tsvector('french', 'courir cours coureur');Résultat :
config | result
--------+----------------------------
simple | 'runner':3 'running':1 'runs':2
english | 'run':1,2,3 ← Stemming : tous → "run"
french | 'cour':1,2,3 ← Stemming : tous → "cour"
-- Voir la configuration par défaut
SHOW default_text_search_config;
-- Résultat typique : pg_catalog.english (ou french selon l'installation)
-- Changer la configuration par défaut pour la session
SET default_text_search_config = 'french';
-- Utiliser to_tsvector sans spécifier la langue (utilise le défaut)
SELECT to_tsvector('Les bases de données');
-- Utilise maintenant la configuration française-- Détails de la configuration française
SELECT
cfgname,
(SELECT dictname FROM pg_ts_dict d
WHERE d.oid = ANY(m.mapdict) LIMIT 1) AS premier_dictionnaire
FROM pg_ts_config c
JOIN pg_ts_config_map m ON m.mapcfg = c.oid
WHERE cfgname = 'french'
LIMIT 5; Chaque configuration associe des types de tokens à des dictionnaires :
-- Voir le mapping complet pour le français
SELECT
tt.alias AS type_token,
tt.description,
ARRAY_AGG(d.dictname ORDER BY m.mapseqno) AS dictionnaires
FROM pg_ts_config c
JOIN pg_ts_config_map m ON m.mapcfg = c.oid
JOIN pg_ts_dict d ON d.oid = ANY(m.mapdict)
JOIN ts_token_type(c.cfgparser) tt ON tt.tokid = m.maptokentype
WHERE c.cfgname = 'french'
GROUP BY tt.alias, tt.description, m.maptokentype
ORDER BY m.maptokentype; Résultat typique pour "french" :
type_token | description | dictionnaires
------------+--------------------+------------------------
asciiword | Word, all ASCII | {french_stem}
word | Word, all letters | {french_stem}
numword | Word, letters+num | {simple}
email | Email address | {simple}
url | URL | {simple}
host | Host | {simple}
Interprétation :
- Les mots (asciiword, word) passent par
french_stem(stemming français) - Les nombres et URLs passent par
simple(pas de transformation) - Les espaces et ponctuation sont ignorés
Les dictionnaires sont appliqués séquentiellement jusqu'à ce que l'un produise un résultat :
Token: "couraient"
↓
[1] french_stem → "cour" ✓ (succès, on s'arrête)
↓
Lexème: "cour"
Si le premier dictionnaire ne produit rien (stop word), le suivant est essayé :
Token: "le"
↓
[1] french_stem → NULL (stop word, aucun résultat)
↓
[2] simple → NULL (pas d'autre dictionnaire)
↓
Lexème: (aucun, token ignoré)
Le dictionnaire simple ne fait aucune transformation : il retourne le token tel quel en minuscules.
-- Créer un dictionnaire simple
CREATE TEXT SEARCH DICTIONARY public.simple_dict (
TEMPLATE = pg_catalog.simple
);
-- Test
SELECT ts_lexize('simple_dict', 'PostgreSQL');
-- Résultat : {postgresql}
SELECT ts_lexize('simple_dict', 'Les');
-- Résultat : {les} (même les stop words sont conservés)Usage : Pour les tokens qu'on ne veut pas transformer (URLs, emails, codes).
Le dictionnaire Snowball applique un algorithme de stemming pour réduire les mots à leur racine.
-- Voir les stemmers Snowball disponibles
SELECT * FROM pg_ts_dict WHERE dictname LIKE '%stem';Algorithmes Snowball :
danish_stem: Danoisdutch_stem: Néerlandaisenglish_stem: Anglaisfinnish_stem: Finnoisfrench_stem: Françaisgerman_stem: Allemandhungarian_stem: Hongroisitalian_stem: Italiennorwegian_stem: Norvégienportuguese_stem: Portugaisromanian_stem: Roumainrussian_stem: Russespanish_stem: Espagnolswedish_stem: Suédoisturkish_stem: Turc
Exemple de stemming français :
-- Tester le stemmer français
SELECT ts_lexize('french_stem', 'couraient');
-- Résultat : {cour}
SELECT ts_lexize('french_stem', 'coureur');
-- Résultat : {cour}
SELECT ts_lexize('french_stem', 'courses');
-- Résultat : {cours}
SELECT ts_lexize('french_stem', 'bases');
-- Résultat : {base}
SELECT ts_lexize('french_stem', 'données');
-- Résultat : {donn}Créer un dictionnaire Snowball personnalisé :
-- Créer un stemmer français avec stop words personnalisés
CREATE TEXT SEARCH DICTIONARY french_custom (
TEMPLATE = snowball,
Language = french,
StopWords = french -- Fichier de stop words (optionnel)
);Les dictionnaires Ispell utilisent des fichiers de dictionnaires morphologiques (comme les correcteurs orthographiques).
-- Créer un dictionnaire Ispell pour le français
CREATE TEXT SEARCH DICTIONARY french_ispell (
TEMPLATE = ispell,
DictFile = french, -- Fichier .dict
AffFile = french, -- Fichier .affix
StopWords = french -- Fichier de stop words
);
-- Les fichiers doivent être dans $SHAREDIR/tsearch_data/
-- Exemple : french.dict, french.affixAvantages Ispell :
- Plus précis que Snowball (connaissance morphologique)
- Gère les irrégularités linguistiques
- Peut faire de la lemmatisation (pas juste du stemming)
Inconvénients :
- Nécessite des fichiers de dictionnaires externes
- Plus lent que Snowball
- Fichiers volumineux
Exemple d'utilisation :
-- Si le dictionnaire est configuré
SELECT ts_lexize('french_ispell', 'couraient');
-- Résultat : {courir} (lemme, pas juste stem)Le dictionnaire synonym remplace des mots par leurs synonymes.
-- Créer un fichier de synonymes : /usr/share/postgresql/16/tsearch_data/synonyms.syn
-- Contenu du fichier :
-- postgres postgresql
-- pgsql postgresql
-- pg postgresql
-- Créer le dictionnaire
CREATE TEXT SEARCH DICTIONARY synonym_dict (
TEMPLATE = synonym,
SYNONYMS = synonyms -- Nom du fichier (sans .syn)
);
-- Test
SELECT ts_lexize('synonym_dict', 'postgres');
-- Résultat : {postgresql}
SELECT ts_lexize('synonym_dict', 'pgsql');
-- Résultat : {postgresql}Format du fichier de synonymes :
# Commentaire
mot_original synonyme
# Exemples
db database
rdbms database
sgbd database
bdd database
Le dictionnaire thesaurus est une version avancée du dictionnaire de synonymes qui gère des phrases multi-mots.
-- Fichier thesaurus.ths
-- Format : phrase originale : liste de synonymes
-- Exemple :
-- postgres sql : postgresql
-- relational database : rdbms
-- artificial intelligence : ai machine_learning
-- Créer le dictionnaire
CREATE TEXT SEARCH DICTIONARY thesaurus_dict (
TEMPLATE = thesaurus,
DictFile = thesaurus, -- Fichier .ths
Dictionary = english_stem -- Dictionnaire sous-jacent pour stemming
);
-- Test
SELECT ts_lexize('thesaurus_dict', 'relational');
-- Résultat : NULL (attente du mot suivant "database")
-- Utilisation via to_tsvector (traite les phrases)
SELECT to_tsvector('thesaurus_config', 'relational database system');
-- Résultat : 'rdbms':1 'system':3Les stop words sont des mots très fréquents et peu significatifs qu'on ignore lors de l'indexation.
Exemples français : le, la, les, un, une, de, du, des, à, au, en, et, ou, mais, etc.
Exemples anglais : the, a, an, in, on, at, to, for, of, with, etc.
Les configurations linguistiques utilisent des fichiers de stop words :
# Localisation typique
/usr/share/postgresql/16/tsearch_data/
# Fichiers
french.stop # Stop words français
english.stop # Stop words anglais
spanish.stop # Stop words espagnol
# etc.-- Tester si un mot est un stop word
SELECT ts_lexize('french_stem', 'le');
-- Résultat : NULL (c'est un stop word)
SELECT ts_lexize('french_stem', 'les');
-- Résultat : NULL (stop word)
SELECT ts_lexize('french_stem', 'postgresql');
-- Résultat : {postgresql} (pas un stop word)Extrait du fichier french.stop :
au
aux
avec
ce
ces
dans
de
des
du
elle
en
et
eux
il
je
la
le
leur
lui
ma
mais
me
même
mes
moi
mon
ne
nos
notre
nous
on
ou
par
pas
pour
qu
que
qui
sa
se
ses
son
sur
ta
te
tes
toi
ton
tu
un
une
vos
votre
vous
-- 1. Créer le fichier /usr/share/postgresql/16/tsearch_data/custom_french.stop
-- Contenu : un mot par ligne
-- Exemple :
-- le
-- la
-- les
-- mon_mot_specifique
-- acronyme_frequent
-- 2. Créer un dictionnaire avec ces stop words
CREATE TEXT SEARCH DICTIONARY french_custom_stop (
TEMPLATE = snowball,
Language = french,
StopWords = custom_french -- Sans l'extension .stop
);
-- 3. L'utiliser dans une configuration- Combiner plusieurs dictionnaires
- Personnaliser le traitement pour votre domaine
- Gérer des cas spécifiques (termes techniques, acronymes)
- Optimiser pour votre application
-- Dictionnaire de synonymes techniques
CREATE TEXT SEARCH DICTIONARY tech_synonyms (
TEMPLATE = synonym,
SYNONYMS = tech_synonyms -- Fichier tech_synonyms.syn
);
-- Dictionnaire de stemming français
-- (déjà existant : french_stem)
-- Dictionnaire simple pour les codes/acronymes
CREATE TEXT SEARCH DICTIONARY simple_dict (
TEMPLATE = pg_catalog.simple
);-- Créer une nouvelle configuration basée sur french
CREATE TEXT SEARCH CONFIGURATION french_tech (
COPY = french -- Copie la configuration française
);
-- Ou créer une configuration from scratch
CREATE TEXT SEARCH CONFIGURATION custom_config (
PARSER = default
);-- Ajouter le dictionnaire de synonymes AVANT le stemmer
ALTER TEXT SEARCH CONFIGURATION french_tech
ALTER MAPPING FOR asciiword, word
WITH tech_synonyms, french_stem;
-- Les tokens "asciiword" et "word" passeront par:
-- 1. tech_synonyms (remplace par synonyme si trouvé)
-- 2. french_stem (stemming si pas de synonyme)-- Test
SELECT to_tsvector('french_tech', 'Le postgresql et le pgsql');
-- Si tech_synonyms.syn contient : pgsql postgresql
-- Résultat : 'postgresql':2,5 (pgsql remplacé par postgresql)
-- Utiliser dans une table
ALTER TABLE articles
ADD COLUMN search_vector tsvector;
UPDATE articles
SET search_vector = to_tsvector('french_tech', titre || ' ' || contenu); -- 1. Dictionnaire de synonymes produits
-- Fichier : /tsearch_data/ecommerce_synonyms.syn
-- Contenu :
-- smartphone telephone
-- portable telephone
-- tel telephone
-- ordi ordinateur
-- pc ordinateur
CREATE TEXT SEARCH DICTIONARY ecommerce_synonyms (
TEMPLATE = synonym,
SYNONYMS = ecommerce_synonyms
);
-- 2. Stop words personnalisés (ignorer marques communes)
-- Fichier : /tsearch_data/ecommerce.stop
-- Contenu : article, produit, neuf, occasion, promo
CREATE TEXT SEARCH DICTIONARY ecommerce_stop (
TEMPLATE = snowball,
Language = french,
StopWords = ecommerce
);
-- 3. Créer la configuration
CREATE TEXT SEARCH CONFIGURATION french_ecommerce (COPY = french);
-- 4. Configurer les mappings
ALTER TEXT SEARCH CONFIGURATION french_ecommerce
ALTER MAPPING FOR asciiword, word
WITH ecommerce_synonyms, ecommerce_stop;
-- 5. Test
SELECT to_tsvector('french_ecommerce', 'smartphone portable Apple neuf');
-- Résultat : 'appl':3 'telephon':1,2
-- "smartphone" et "portable" → "telephon"
-- "neuf" → ignoré (stop word)
-- "Apple" → "appl" (stemming)-- Table multilingue
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
titre VARCHAR(200),
contenu TEXT,
langue VARCHAR(10), -- 'fr', 'en', 'es', etc.
search_vector tsvector
);
-- Trigger intelligent qui choisit la configuration selon la langue
CREATE OR REPLACE FUNCTION articles_multilingual_trigger()
RETURNS trigger AS $$
DECLARE
config regconfig;
BEGIN
-- Déterminer la configuration selon la langue
config := CASE NEW.langue
WHEN 'fr' THEN 'french'::regconfig
WHEN 'en' THEN 'english'::regconfig
WHEN 'es' THEN 'spanish'::regconfig
WHEN 'de' THEN 'german'::regconfig
WHEN 'it' THEN 'italian'::regconfig
ELSE 'simple'::regconfig -- Fallback
END;
-- Créer le tsvector avec la bonne configuration
NEW.search_vector := to_tsvector(config, COALESCE(NEW.titre, '') || ' ' || COALESCE(NEW.contenu, ''));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tsvector_update
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW EXECUTE FUNCTION articles_multilingual_trigger();
-- Index
CREATE INDEX idx_articles_search ON articles USING GIN(search_vector);
-- Insertion
INSERT INTO articles (titre, contenu, langue) VALUES
('Guide PostgreSQL', 'PostgreSQL est puissant', 'fr'),
('PostgreSQL Guide', 'PostgreSQL is powerful', 'en'),
('Guía PostgreSQL', 'PostgreSQL es potente', 'es');
-- Recherche multilingue
SELECT titre, langue
FROM articles
WHERE search_vector @@ to_tsquery('french', 'puissant')
OR search_vector @@ to_tsquery('english', 'powerful')
OR search_vector @@ to_tsquery('spanish', 'potente');-- Table avec colonnes par langue
CREATE TABLE produits (
id SERIAL PRIMARY KEY,
nom_fr VARCHAR(200),
description_fr TEXT,
nom_en VARCHAR(200),
description_en TEXT,
nom_es VARCHAR(200),
description_es TEXT,
search_vector_fr tsvector,
search_vector_en tsvector,
search_vector_es tsvector
);
-- Triggers séparés pour chaque langue
CREATE OR REPLACE FUNCTION produits_fr_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector_fr := to_tsvector('french',
COALESCE(NEW.nom_fr, '') || ' ' || COALESCE(NEW.description_fr, '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tsvector_fr_update
BEFORE INSERT OR UPDATE ON produits
FOR EACH ROW EXECUTE FUNCTION produits_fr_trigger();
-- Répéter pour EN et ES...
-- Index séparés
CREATE INDEX idx_produits_search_fr ON produits USING GIN(search_vector_fr);
CREATE INDEX idx_produits_search_en ON produits USING GIN(search_vector_en);
CREATE INDEX idx_produits_search_es ON produits USING GIN(search_vector_es);
-- Recherche par langue
SELECT nom_fr, description_fr
FROM produits
WHERE search_vector_fr @@ plainto_tsquery('french', 'chaussure rouge'); Pour des cas simples où on veut indexer dans plusieurs langues simultanément :
-- Créer une configuration qui combine plusieurs langues
CREATE TEXT SEARCH CONFIGURATION multilang (PARSER = default);
-- Mapper les tokens vers plusieurs stemmers
ALTER TEXT SEARCH CONFIGURATION multilang
ADD MAPPING FOR asciiword, word
WITH french_stem, english_stem, spanish_stem;
-- Utilisation
SELECT to_tsvector('multilang', 'running courir corriendo');
-- Résultat : 'cour':2 'corr':3 'run':1
-- (chaque mot est stemmed par son stemmer approprié)-- Fonction de détection basique (simplifié)
CREATE OR REPLACE FUNCTION detect_language(text TEXT)
RETURNS regconfig AS $$
DECLARE
config regconfig;
BEGIN
-- Détection basique par mots communs
IF text ~* '\m(the|is|are|and)\M' THEN
config := 'english';
ELSIF text ~* '\m(le|la|les|est|sont|et)\M' THEN
config := 'french';
ELSIF text ~* '\m(el|la|los|las|es|son|y)\M' THEN
config := 'spanish';
ELSE
config := 'simple';
END IF;
RETURN config;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- Utilisation dans un trigger
CREATE OR REPLACE FUNCTION articles_auto_lang_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector := to_tsvector(
detect_language(NEW.contenu),
COALESCE(NEW.titre, '') || ' ' || COALESCE(NEW.contenu, '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;-- Dictionnaire de préservation d'acronymes
-- Fichier : tech_preserve.syn
-- Contenu :
-- sql SQL
-- html HTML
-- css CSS
-- api API
-- json JSON
-- xml XML
CREATE TEXT SEARCH DICTIONARY tech_preserve (
TEMPLATE = synonym,
SYNONYMS = tech_preserve
);
-- Configuration technique
CREATE TEXT SEARCH CONFIGURATION tech_doc (COPY = english);
ALTER TEXT SEARCH CONFIGURATION tech_doc
ALTER MAPPING FOR asciiword
WITH tech_preserve, english_stem;
-- Test
SELECT to_tsvector('tech_doc', 'This API uses JSON and SQL');
-- Résultat : 'API':2 'JSON':4 'SQL':6 'use':3
-- Acronymes préservés en majuscules-- Synonymes médicaux
-- Fichier : medical_synonyms.syn
-- Contenu :
-- imc indice_masse_corporelle
-- avc accident_vasculaire_cerebral
-- ecg electrocardiogramme
-- irm imagerie_resonance_magnetique
CREATE TEXT SEARCH DICTIONARY medical_synonyms (
TEMPLATE = synonym,
SYNONYMS = medical_synonyms
);
-- Stop words médicaux (mots trop fréquents)
-- Fichier : medical.stop
-- Contenu : patient, traitement, diagnostic, symptome
CREATE TEXT SEARCH DICTIONARY medical_stem (
TEMPLATE = snowball,
Language = french,
StopWords = medical
);
-- Configuration médicale
CREATE TEXT SEARCH CONFIGURATION french_medical (COPY = french);
ALTER TEXT SEARCH CONFIGURATION french_medical
ALTER MAPPING FOR asciiword, word
WITH medical_synonyms, medical_stem;
-- Test
SELECT to_tsvector('french_medical', 'Le patient a un IMC élevé après AVC');
-- Résultat : 'accident_vasculaire_cerebral':7 'elev':5 'indice_masse_corporelle':4Par défaut, PostgreSQL respecte les accents dans le Full-Text Search.
-- Test standard
SELECT to_tsvector('french', 'café') @@ to_tsquery('french', 'cafe');
-- Résultat : false (café ≠ cafe)
-- Solution 1 : Extension unaccent
CREATE EXTENSION IF NOT EXISTS unaccent;
-- Créer un dictionnaire qui enlève les accents
CREATE TEXT SEARCH DICTIONARY french_unaccent (
TEMPLATE = unaccent
);
-- Configuration sans accents
CREATE TEXT SEARCH CONFIGURATION french_no_accent (COPY = french);
ALTER TEXT SEARCH CONFIGURATION french_no_accent
ALTER MAPPING FOR asciiword, word
WITH french_unaccent, french_stem;
-- Test
SELECT to_tsvector('french_no_accent', 'café') @@
to_tsquery('french_no_accent', 'cafe');
-- Résultat : true (accent enlevé)-- Debug complet du traitement
SELECT * FROM ts_debug('french', 'Les bases de données PostgreSQL');Résultat :
alias | description | token | dictionaries | dictionary | lexemes
----------+------------------+------------+---------------+-------------+---------
asciiword | Word, all ASCII | Les | {french_stem} | french_stem | {}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | bases | {french_stem} | french_stem | {base}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | de | {french_stem} | french_stem | {}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | données | {french_stem} | french_stem | {donn}
blank | Space symbols | | {} | |
asciiword | Word, all ASCII | PostgreSQL | {french_stem} | french_stem | {postgresql}
Colonnes importantes :
token: Mot originaldictionaries: Dictionnaires disponibles pour ce typedictionary: Dictionnaire utilisélexemes: Résultat (vide = stop word)
-- Tester directement un dictionnaire
SELECT ts_lexize('french_stem', 'données');
-- Résultat : {donn}
SELECT ts_lexize('french_stem', 'le');
-- Résultat : NULL (stop word)
-- Tester plusieurs mots
SELECT word, ts_lexize('french_stem', word) AS lexemes
FROM unnest(ARRAY['courir', 'couraient', 'coureur', 'course']) AS word; Résultat :
word | lexemes
-----------+---------
courir | {cour}
couraient | {cour}
coureur | {cour}
course | {cours}
-- Voir les différences entre configurations
SELECT
'simple' AS config,
to_tsvector('simple', 'Les coureurs courent rapidement') AS result
UNION ALL
SELECT
'french',
to_tsvector('french', 'Les coureurs courent rapidement')
UNION ALL
SELECT
'english',
to_tsvector('english', 'Les coureurs courent rapidement');Ordre de rapidité (du plus rapide au plus lent) :
- Simple : Aucun traitement (très rapide)
- Snowball : Algorithme de stemming (rapide)
- Synonym : Lookup dans un fichier (rapide pour petits fichiers)
- Ispell : Analyse morphologique (lent)
- Thesaurus : Phrases multi-mots (très lent)
-- Benchmark simplifié
EXPLAIN ANALYZE
SELECT COUNT(*) FROM articles
WHERE to_tsvector('simple', contenu) @@ to_tsquery('simple', 'postgresql');
-- Temps : ~50ms
EXPLAIN ANALYZE
SELECT COUNT(*) FROM articles
WHERE to_tsvector('french', contenu) @@ to_tsquery('french', 'postgresql');
-- Temps : ~65ms (15% plus lent à cause du stemming)-- ✅ BON : Colonne précalculée
ALTER TABLE articles ADD COLUMN search_vector tsvector;
UPDATE articles SET search_vector = to_tsvector('french', contenu);
CREATE INDEX idx_search ON articles USING GIN(search_vector);
SELECT * FROM articles WHERE search_vector @@ query;
-- Très rapide : lecture d'index
-- ❌ LENT : Calcul à chaque requête
SELECT * FROM articles
WHERE to_tsvector('french', contenu) @@ query;
-- Lent : recalcul du tsvector à chaque fois-- Pour du contenu sans stemming nécessaire (codes, IDs)
to_tsvector('simple', code_produit)
-- Pour du texte en langue naturelle
to_tsvector('french', description)-- ❌ Trop de dictionnaires (lent)
ALTER TEXT SEARCH CONFIGURATION my_config
ALTER MAPPING FOR asciiword
WITH synonym1, synonym2, thesaurus1, ispell1, french_stem;
-- Chaque token passe par 5 dictionnaires !
-- ✅ Uniquement les nécessaires
ALTER TEXT SEARCH CONFIGURATION my_config
ALTER MAPPING FOR asciiword
WITH synonym1, french_stem;
-- 2 dictionnaires suffisent généralement-- ✅ BON : Configuration appropriée
to_tsvector('french', texte_francais)
to_tsvector('english', english_text)
-- ❌ MAUVAIS : Mauvaise configuration
to_tsvector('english', texte_francais) -- Stemming anglais sur français !-- Documenter avec des commentaires
COMMENT ON TEXT SEARCH CONFIGURATION french_tech IS
'Configuration française avec synonymes techniques pour le secteur IT';
COMMENT ON TEXT SEARCH DICTIONARY tech_synonyms IS
'Synonymes techniques : postgres→postgresql, pgsql→postgresql, etc.';-- Suite de tests
CREATE TABLE test_search_config (
id SERIAL PRIMARY KEY,
input TEXT,
expected_lexemes TEXT[],
config regconfig
);
-- Insérer des cas de test
INSERT INTO test_search_config (input, expected_lexemes, config) VALUES
('postgresql', ARRAY['postgresql'], 'french'),
('bases de données', ARRAY['base', 'donn'], 'french'),
('couraient', ARRAY['cour'], 'french');
-- Vérifier
SELECT
input,
expected_lexemes,
to_tsvector(config, input) AS actual_tsvector,
expected_lexemes = ARRAY(SELECT unnest(to_tsvector(config, input))) AS passed
FROM test_search_config;# Structure recommandée
/usr/share/postgresql/16/tsearch_data/
├── french.stop # Stop words français standard
├── custom_french.stop # Stop words personnalisés
├── tech_synonyms.syn # Synonymes techniques
├── medical_synonyms.syn # Synonymes médicaux
└── ecommerce.syn # Synonymes e-commerce
# Versionner ces fichiers
git add tsearch_data/
git commit -m "Add custom dictionaries" -- Trigger avec fallback
CREATE OR REPLACE FUNCTION safe_tsvector_trigger() RETURNS trigger AS $$
DECLARE
config regconfig;
BEGIN
BEGIN
config := (NEW.langue || '_text_search')::regconfig;
EXCEPTION WHEN OTHERS THEN
config := 'simple'::regconfig; -- Fallback sur 'simple'
END;
NEW.search_vector := to_tsvector(config, NEW.contenu);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;-- Voir toutes les configurations disponibles
SELECT cfgname FROM pg_ts_config;
-- Utiliser une configuration
to_tsvector('french', texte)
to_tsquery('french', 'recherche')
-- Configuration par défaut
SHOW default_text_search_config;
SET default_text_search_config = 'french'; | Type | Description | Exemple |
|---|---|---|
simple |
Pas de transformation | Codes, IDs |
snowball |
Stemming algorithmique | Texte général |
ispell |
Morphologie (dictionnaires) | Haute précision |
synonym |
Remplacement 1:1 | Synonymes simples |
thesaurus |
Phrases multi-mots | Expressions |
unaccent |
Suppression accents | Insensible accents |
-- 1. Créer dictionnaires
CREATE TEXT SEARCH DICTIONARY mon_dict (
TEMPLATE = snowball,
Language = french,
StopWords = custom
);
-- 2. Créer configuration
CREATE TEXT SEARCH CONFIGURATION ma_config (COPY = french);
-- 3. Modifier mappings
ALTER TEXT SEARCH CONFIGURATION ma_config
ALTER MAPPING FOR asciiword, word
WITH mon_dict, french_stem;
-- 4. Utiliser
to_tsvector('ma_config', texte)-- Approche 1 : Colonne de langue
CREATE TABLE articles (
langue VARCHAR(10),
search_vector tsvector
);
-- Trigger qui choisit la config selon langue
-- (voir section 7 pour code complet)
-- Approche 2 : Colonnes séparées
CREATE TABLE produits (
search_vector_fr tsvector,
search_vector_en tsvector,
search_vector_es tsvector
);-- Analyse complète
SELECT * FROM ts_debug('french', texte);
-- Test d'un dictionnaire
SELECT ts_lexize('french_stem', 'mot');
-- Test d'une configuration
SELECT to_tsvector('french', texte);Les dictionnaires et les configurations linguistiques sont les fondations du Full-Text Search multilingue et personnalisable dans PostgreSQL.
Points clés à retenir :
-
Configurations pré-définies : 20+ langues supportées (french, english, spanish, etc.)
- Stemming automatique
- Stop words intégrés
- Prêtes à l'emploi
-
Types de dictionnaires :
- Simple : Pas de transformation
- Snowball : Stemming algorithmique (rapide)
- Ispell : Morphologie (précis mais lent)
- Synonym : Remplacements simples
- Thesaurus : Phrases complexes
-
Personnalisation :
- Créer des dictionnaires spécifiques à votre domaine
- Combiner plusieurs dictionnaires
- Adapter les stop words
-
Multilinguisme :
- Colonne de langue + trigger dynamique
- Colonnes séparées par langue
- Configuration unifiée (cas simples)
-
Performance :
- Pré-calculer les tsvector (colonne dédiée)
- Limiter le nombre de dictionnaires
- Choisir le bon type selon les besoins
Les dictionnaires permettent d'adapter PostgreSQL Full-Text Search à n'importe quel contexte linguistique ou métier, tout en conservant d'excellentes performances. C'est ce qui en fait une solution véritablement professionnelle et polyvalente.
Prochaine étape : Explorez les index GIN avancés et les optimisations de performance pour des systèmes de recherche à grande échelle !
Ressources complémentaires :
- Documentation dictionnaires : https://www.postgresql.org/docs/current/textsearch-dictionaries.html
- Configurations : https://www.postgresql.org/docs/current/textsearch-configuration.html
- Snowball stemmers : https://snowballstem.org/
- Ispell dictionaries : https://www.postgresql.org/docs/current/textsearch-ispell.html