Documentation PostgreSQL 8.3.23 > Langage SQL > Recherche plein texte > Dictionnaires | |
Analyseurs | Exemple de configuration |
Les dictionnaires sont utilisés pour éliminer des mots qui ne devraient pas être considérés dans une recherche (termes courants), et pour normaliser des mots pour que des formes dérivées de ce même mot établissent une correspondance. Un mot normalisé avec succès est appelé un lexeme. En dehors d'améliorer la qualité de la recherche, la normalisation et la suppression des termes courants réduisent la taille de la représentation d'un document en tsvector, et donc améliorent les performances. La normalisation n'a pas toujours une signification linguistique et dépend habituellement de la sémantique de l'application.
Quelques exemples de normalisation :
Linguistique - les dictionnaires ispell tentent de réduire les mots en entrée en une forme normalisée ; les dictionnaires stemmer suppriment la fin des mots
Les URL peuvent être réduites pour établir certaines correspondance :
http://www.pgsql.ru/db/mw/index.html
http://www.pgsql.ru/db/mw/
http://www.pgsql.ru/db/../db/mw/index.html
Les noms de couleur peuvent être remplacés par leur valeur hexadécimale, par exemple red, green, blue, magenta -> FF0000, 00FF00, 0000FF, FF00FF
En cas d'indexation de nombre, nous pouvons supprimer certains chiffres à fraction pour réduire les nombres possibles, donc par exemple 3.14159265359, 3.1415926, 3.14 seront identiques après normalisation si seuls deux chiffres sont conservés après le point décimal.
Un dictionnaire est un programme qui accepte un jeton en entrée et renvoie :
un tableau de lexemes si le jeton en entrée est connu dans le dictionnaire (notez qu'un jeton peut produire plusieurs lexemes)
un tableau vide si le dictionnaire connaît le jeton mais que ce dernier est un terme courant
NULL si le dictionnaire n'a pas reconnu le jeton en entrée
PostgreSQL™ fournit des dictionnaires prédéfinis pour de nombreuses langues. Il existe aussi plusieurs modèles prédéfinis qui peuvent être utilisés pour créer de nouveaux dictionnaires avec des paramètres personnalisés. Chaque modèle prédéfini de dictionnaire est décrit ci-dessous. Si aucun modèle ne convient, il est possible d'en créer de nouveaux ; voir le répertoire contrib/ de PostgreSQL™ pour des exemples.
Une configuration de recherche plein texte lie un analyseur avec un ensemble de dictionnaires pour traiter les jetons en sortie de l'analyseur. Pour chaque type de jeton que l'analyseur peut renvoyer, une liste séparée de dictionnaires est indiquée par la configuration. Quand un jeton de ce type est trouvée par l'analyseur, chaque dictionnaire de la liste est consulté jusqu'à ce qu'un dictionnaire le reconnaisse comme un mot connu. S'il est identifié comme un terme courant ou si aucun dictionnaire ne le reconnait, il sera ignoré et non indexé. La règle générale pour la configuration de la liste des dictionnaires est de placer en premier les dictionnaires les plus précis, les plus spécifiques, puis les dictionnaires généralistes, en finissant avec un dictionnaire le plus général possible, comme par exemple un stemmer Snowball ou simple, qui reconnait tout. Par exemple, pour une recherche en astronomie (configuration astro_en), vous pouvez lier le type de jeton asciiword (mot ASCII) vers un dictionnaire des synonymes des termes de l'astronomie, un dictionnaire anglais généraliste et un stemmer Snowball anglais :
ALTER TEXT SEARCH CONFIGURATION astro_en ADD MAPPING FOR asciiword WITH astrosyn, english_ispell, english_stem;
Les termes courants sont des mots très courants, apparaissant dans pratiquement chaque document et n'ont donc pas de valeur discriminatoire. Du coup, ils peuvent être ignorés dans le contexte de la recherche plein texte. Par exemple, tous les textes anglais contiennent des mots comme a et the, donc il est inutile de les stocker dans un index. Néanmoins, les termes courants n'affectent pas les positions dans tsvector, ce qui affecte le score :
SELECT to_tsvector('english','in the list of stop words'); to_tsvector ---------------------------- 'list':3 'stop':5 'word':6
Les positions 1, 2, 4 manquantes sont dûes aux termes courants. Les scores calculés pour les documents avec et sans termes courants sont vraiment différents :
SELECT ts_rank_cd (to_tsvector('english','in the list of stop words'), to_tsquery('list & stop')); ts_rank_cd ------------ 0.05 SELECT ts_rank_cd (to_tsvector('english','list stop words'), to_tsquery('list & stop')); ts_rank_cd ------------ 0.1
C'est au dictionnaire de savoir comment traiter les mots courants. Par exemple, les dictionnaires Ispell normalisent tout d'abord les mots puis cherchent les termes courants alors que les stemmers Snowball vérifient d'abord leur liste de termes courants. La raison de leur comportement différent est qu'ils tentent de réduire le bruit.
Le modèle du dictionnaire simple opère en convertissant le jeton en entrée en minuscule puis en vérifiant s'il fait partie de la liste des mots courants qu'il a sur fichier. S'il est trouvé dans ce fichier, un tableau vide est renvoyé. Le jeton sera alors ignoré. Dans le cas contraire, la forme minuscule du mot est renvoyé en tant que lexeme normalisé. Autrement, le dictionnaire peut être configuré pour rapporter les termes courants comme étant non reconnus, ce qui permet de les passer au prochain dictionnaire de la liste.
Voici un exemple d'une définition de dictionnaire utilisant le modèle simple :
CREATE TEXT SEARCH DICTIONARY public.simple_dict ( TEMPLATE = pg_catalog.simple, STOPWORDS = english );
Dans ce cas, english est le nom de base du fichier contenant les termes courants. Le nom complet du fichier sera donc $SHAREDIR/tsearch_data/english.stop, où $SHAREDIR est le répertoire des données partagées de l'installation de PostgreSQL™ (souvent /usr/local/share/postgresql mais utilisez pg_config --sharedir pour vous en assurer). Le format du fichier est une simple liste de mots, un mot par ligne. Les lignes vides et les espaces en fin de mot sont ignorés. Les mots en majuscule sont basculés en minuscule, mais aucun autre traitement n'est réalisé sur le contenu de ce fichier.
Maintenant, nous pouvons tester notre dictionnaire :
SELECT ts_lexize('public.simple_dict','YeS'); ts_lexize ----------- {yes} SELECT ts_lexize('public.simple_dict','The'); ts_lexize ----------- {}
Nous pouvons aussi choisir de renvoyer NULL à la place du mot en minuscule s'il n'est pas trouvé dans le fichier des termes courants. Ce comportement est sélectionné en configurant le paramètre Accept du dictionnaire à false. En continuant l'exemple :
ALTER TEXT SEARCH DICTIONARY public.simple_dict ( Accept = false ); SELECT ts_lexize('public.simple_dict','YeS'); ts_lexize ----------- SELECT ts_lexize('public.simple_dict','The'); ts_lexize ----------- {}
Avec le paramètrage par défaut d'Accept (à savoir, true), il est préférable de placer un dictionnaire simple à la fin de la liste des dictionnaires. Accept = false est seulement utile quand il y a au moins un dictionnaire après celui-ci.
La plupart des types de dictionnaires se basent sur des fichiers de configuration, comme les fichiers de termes courants. Ces fichiers doivent être dans l'encodage UTF-8. Ils seront traduit vers l'encodage actuelle de la base de données, si elle est différente, quand ils seront lus.
Habituellement, une session lira un fichier de configuration du dictionnaire une seule fois, lors de la première utilisation. Si vous modifiez un fichier de configuration et que vous voulez forcer la prise en compte des modifications par les sessions en cours, exécutez une commande ALTER TEXT SEARCH DICTIONARY sur le dictionnaire. Cela peut être une mise à jour « à vide », donc sans réellement modifier des valeurs.
Ce modèle de dictionnaire est utilisé pour créer des dictionnaires qui remplacent un mot par un synonyme. Les phrases ne sont pas supportées (utilisez le modèle thésaurus pour cela, Section 12.6.4, « Dictionnaire thésaurus »). Un dictionnaire des synonyme peut être utilisé pour contourner des problèmes linguistiques, par exemple pour empêcher un dictionnaire stemmer anglais de réduire le mot « Paris » en 'pari'. Il suffit d'avoir une ligne Paris paris dans le dictionnaire des synonymes et de le placer avant le dictionnaire english_stem :
SELECT * FROM ts_debug('english', 'Paris'); alias | description | token | dictionaries | dictionary | lexemes -----------+-----------------+-------+----------------+--------------+--------- asciiword | Word, all ASCII | Paris | {english_stem} | english_stem | {pari} CREATE TEXT SEARCH DICTIONARY my_synonym ( TEMPLATE = synonym, SYNONYMS = my_synonyms ); ALTER TEXT SEARCH CONFIGURATION english ALTER MAPPING FOR asciiword WITH my_synonym, english_stem; SELECT * FROM ts_debug('english', 'Paris'); alias | description | token | dictionaries | dictionary | lexemes -----------+-----------------+-------+---------------------------+------------+--------- asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}
Le seul paramètre requis par le modèle synonym est SYNONYMS, qui est le nom de base de son fichier de configuration -- my_synonyms dans l'exemple ci-dessus. Le nom complet du fichier sera $SHAREDIR/tsearch_data/my_synonyms.syn (où $SHAREDIR correspond au répertoire des données partagées de l'installation de PostgreSQL™). Le format du fichier est une ligne par mot à substituer, avec le mot suivi par son synonyme séparé par un espace blanc. Les lignes vierges et les espaces après les mots sont ignorés, les lettres majuscules sont mises en minuscules.
Un dictionnaire thésaurus (parfois abrévié en TZ) est un ensemble de mots qui incluent des informations sur les relations des mots et des phrases, par exemple des termes plus lointains (BT), plus proches (NT), des termes préférés, des termes non aimés, des termes en relation, etc.
De façon simple, un dictionnaire thésaurus remplace tous les termes par des termes préférés et, en option, conserve les termes originaux pour l'indexage. L'implémentation actuelle du dictionnaire thésaurus par PostgreSQL™ est une extension du dictionnaire des synonymes avec un support additionnel des phrases. Un dictionnaire thésaurus nécessite un fichier de configuration au format suivant :
# ceci est un commentaire mots(s) : mot(s) indexé(s) d'autre(s) mot(s) : d'autre(s) mot(s) indexé(s) ...
où le deux-points (:) agit comme un délimiteur entre une phrase et son remplacement.
Un dictionnaire thésaurus utilise un sous-dictionnaire (qui est spécifié dans la configuration du dictionnaire) pour normaliser le texte en entrée avant la vérification des correspondances de phrases. Un seul sous-dictionnaire est sélectionnable. Une erreur est renvoyée si le sous-dictionnaire échoue dans la reconnaissance d'un mot. Dans ce cas, vous devez supprimer l'utilisation du mot ou le faire connaître au sous-dictionnaire. Vous pouvez placer une astérisque (*) devant un mot indexé pour ignorer l'utilisation du sous-dictionnaire mais tous les mots doivent être connus du sous-dictionnaire.
Le dictionnaire thésaurus choisit la plus grande correspondance s'il existe plusieurs phrases correspondant à l'entrée.
Les mots spécifiques reconnus par le sous-dictionnaire ne peuvent pas être précisés ; à la place, utilisez ? pour marquer tout emplacement où un terme courant peut apparaître. Par exemple, en supposant que a et the sont des termes courants d'après le sous-dictionnaire :
? one ? two : swsw
correspond à a one the two et à the one a two. Les deux pourraient être remplacés par swsw.
Comme un dictionnaire thésaurus a la possibilité de reconnaître des phrases, il doit se rappeler son état et interagir avec l'analyseur. Un dictionnaire thésaurus utilise ces assignements pour vérifier s'il doit gérer le mot suivant ou arrêter l'accumulation. Le dictionnaire thésaurus doit être configuré avec attention. Par exemple, si le dictionnaire thésaurus s'occupe seulement du type de jeton asciiword, alors une définition du dictionnaire thésaurus comme one 7 ne fonctionnera pas car le type de jeton uint n'est pas affecté au dictionnaire thésaurus.
Les thésaurus sont utilisés lors des indexages pour que toute modification dans les paramètres du dictionnaire thésaurus nécessite un réindexage. Pour la plupart des autres types de dictionnaire, de petites modifications comme l'ajout ou la suppression de termes courants ne demandent pas un réindexage.
Pour définir un nouveau dictionnaire thésaurus, utilisez le modèle thesaurus. Par exemple :
CREATE TEXT SEARCH DICTIONARY thesaurus_simple ( TEMPLATE = thesaurus, DictFile = mythesaurus, Dictionary = pg_catalog.english_stem );
Dans ce cas :
thesaurus_simple est le nom du nouveau dictionnaire
mythesaurus est le nom de base du fichier de configuration du thésaurus. (Son nom complet est $SHAREDIR/tsearch_data/mythesaurus.ths, où $SHAREDIR est remplacé par le répertoire des données partagées de l'installation.)
pg_catalog.english_stem est le sous-dictionnaire (ici un stemmer Snowball anglais) à utiliser pour la normalisation du thésaurus. Notez que le sous-dictionnaire aura sa propre configuration (par exemple, les termes courants) qui n'est pas affichée ici.
Maintenant, il est possible de lier le dictionnaire du thésaurus thesaurus_simple aux types de jeton désirés dans une configuration, par exemple :
ALTER TEXT SEARCH CONFIGURATION russian ALTER MAPPING FOR asciiword, asciihword, hword_asciipart WITH thesaurus_simple;
Considérez un thésaurus d'astronomie thesaurus_astro, contenant quelques combinaisons de mots d'astronomie :
supernovae stars : sn crab nebulae : crab
Ci-dessous, nous créons un dictionnaire et lions certains types de jeton à un thésaurus d'astronomie et à un stemmer anglais :
CREATE TEXT SEARCH DICTIONARY thesaurus_astro ( TEMPLATE = thesaurus, DictFile = thesaurus_astro, Dictionary = english_stem ); ALTER TEXT SEARCH CONFIGURATION russian ALTER MAPPING FOR asciiword, asciihword, hword_asciipart WITH thesaurus_astro, english_stem;
Maintenant, nous pouvons voir comment cela fonctionne. ts_lexize n'est pas très utile pour tester un thésaurus car elle traite l'entrée en tant que simple jeton. À la place, nous pouvons utiliser plainto_tsquery et to_tsvector qui cassera les chaînes en entrée en plusieurs jetons :
SELECT plainto_tsquery('supernova star'); plainto_tsquery ----------------- 'sn' SELECT to_tsvector('supernova star'); to_tsvector ------------- 'sn':1
En principe, il es possible d'utiliser to_tsquery si vous placez l'argument entre guillemets :
SELECT to_tsquery('''supernova star'''); to_tsquery ------------ 'sn'
Notez que supernova star établit une correspondance avec supernovae stars dans thesaurus_astro car nous avions indiqué le stemmer english_stem dans la définition du thésaurus. Le stemmer a supprimé e et s.
Pour indexer la phrase originale ainsi que son substitut, incluez-le dans la partie droite de la définition :
supernovae stars : sn supernovae stars SELECT plainto_tsquery('supernova star'); plainto_tsquery ----------------------------- 'sn' & 'supernova' & 'star'
Le modèle de dictionnaire Ispell ajoute le support des dictionnaires morphologiques qui peuvent normaliser plusieurs formes linguisitiques différentes d'un mot en un même lexeme. Par exemple, un dictionnaire Ispell anglais peut établir une correspondance avec toutes les déclinaisons et conjugaisons du terme bank, c'est-à-dire banking, banked, banks, banks' et bank's.
La distribution standard de PostgreSQL™ n'inclut aucun des fichiers de configuration Ispell. Les dictionnaires sont disponibles pour un grand nombre de langues à partir du site web Ispell. De plus, certains formats de fichiers dictionnaires plus modernes sont supportés -- MySpell (OO < 2.0.1) et Hunspell (OO >= 2.0.2). Une large liste de dictionnaires est disponible sur le Wiki d'OpenOffice .
Pour créer un dictionnaire Ispell, utilisez le modèle interne Ispell et précisez plusieurs paramètres :
CREATE TEXT SEARCH DICTIONARY english_ispell ( TEMPLATE = ispell, DictFile = english, AffFile = english, StopWords = english );
Ici, DictFile, AffFile et StopWords indiquent les noms de base des fichiers dictionnaire, affixes et termes courants. Le fichier des termes courants a le même format qu'indiqué ci-dessus pour le type de dictionnaire simple. Le format des autres fichiers n'est pas indiqué ici mais est disponible sur les sites web mentionnés ci-dessus.
Les dictionnaires Ispell reconnaissent habituellement un ensemble limité de mots, pour qu'ils puissent être suivis par un dictionnaire encore plus généraliste ; par exemple un dictionnaire Snowball qui reconnaît tout.
Les dictionnaires Ispell supportent la séparation des mots composés. C'est une fonctionnaité intéressante et PostgreSQL™ la supporte. Notez que le fichier d'affixes doit indiquer une option spéciale qui marque les mots du dictionnaire qui peuvent participer à une formation composée :
compoundwords controlled z
Voici quelques exemples en norvégien :
SELECT ts_lexize('norwegian_ispell', 'overbuljongterningpakkmesterassistent'); {over,buljong,terning,pakk,mester,assistent} SELECT ts_lexize('norwegian_ispell', 'sjokoladefabrikk'); {sjokoladefabrikk,sjokolade,fabrikk}
MySpell ne supporte pas les mots composés. Hunspell a un support sophistiqué des mots composés. Actuellement, PostgreSQL™ implémente seulement les opérations basiques de Hunspell pour les mots composés.
Le modèle de dictionnaire Snowball est basé sur le projet de Martin Porter, inventeur du populaire algorithme stemming de Porter pour l'anglais. Snowball propose maintenant des algorithmes stemming pour un grand nombre de langues (voir le site Snowball pour plus d'informations). Chaque algorithme sait comment réduire les variantes standard d'un mot vers une base, ou stem, en rapport avec la langue. Un dictionnaire Snowball réclame un paramètre langue pour identifier le stemmer à utiliser et, en option, un nom de fichier des termes courants donnant une liste de mots à éliminer. (Les listes de termes courants au standard PostgreSQL™ sont aussi fournies par le projet Snowball.) Par exemple, il existe un équivalent de la définition interne en
CREATE TEXT SEARCH DICTIONARY english_stem ( TEMPLATE = snowball, Language = english, StopWords = english );
Le format du fichier des termes courants est identique à celui déjà expliqué.
Un dictionnaire Snowball reconnaît tout, qu'il soit ou non capable de simplifier le mot, donc il doit être placé en fin de la liste des dictionnaires. Il est inutile de l'avoir avant tout autre dictionnaire car un jeton ne passera jamais au prochain dictionnaire.