Télécharger Installer Présentation Architecture Serveur Applications Bases de documents Entrepôt Multilinguisme Analyseurs Débuter Configuration Indexation Recherche OAI Javadoc Référence API-XSP Migration Schemas Performances | Les analyseursEn informatique documentaire, on est généralement amené à gérer l'indexation et la recherche sur du plein-texte, autrement nommé "texte intégral", "texte libre", "texte rédigé"... Comme il est hors de question d'indexer et donc de proposer des requêtes sur des phrases, des paragraphes voire des textes entiers, il est nécessaire de faire subir un traitement préalable au texte : l'analyse. Dans SDX, les champs (ou index) qui bénéficient d'une analyse sont définis ainsi dans les fichiers de configuration des applications (application.xconf) : <sdx:field name="champ" type="word"> Les linguistes bondiront certainement face à l'intitulé word, on ne peut plus flou. On aurait pu utiliser un intitulé moins sémantisé ou sémantisé sur le plan informatique, tokenized par exemple. Peu importe. SDX ne proposant pour l'instant qu'une indexation Lucene, l'analyse repose entièrement sur les API d'analyse de ce logiciel. Le concept étant suffisament générique, ces API pourraient servir à tout autre moteur d'indexation. C'est pourquoi nous allons le détailler. La classe org.apache.lucene.analysis.Analyzer est naturellement au coeur du processus d'analyse et en particulier son unique méthode, disposant de deux signatures (dont l'une est dépréciée), tokenStream . Comme son nom l'indique, cette méthode a pour but de fournir un flux de jetons (tokens) pour un champ donné à partir d'un java.io.Reader . Ce Reader permet une très grande abstraction : il peut bien évidemment lire un flux textuel mais aussi tout autre type de flux si bien que l'analyse d'une image ou d'un son serait tout à fait concevable ! La plupart du temps cependant, le Reader que SDX fournira à l'analyseur sera celui fourni par le parseur du document XML généré par la XSLT d'indexation. En sortie, l'analyseur doit fournir un org.apache.lucene.analysis.TokenStream , c'est à dire une suite de org.apache.lucene.analysis.Token . Cet objet, finalité du processus d'analyse, possède les propriétés suivantes :
La première tâche que devra remplir un Analyzer consistera à découper (tokeniser) le flux reçu par le Reader. A cet effet, on utilisera généralement un descendant de la classe org.apache.lucene.analysis.Tokenizer charger de découper le texte en Tokens, sur les espaces ou les signes de ponctuation par exemple. Il va de soi que le découpage des écritures sans espaces (chinois, égyptien ancien....) relève d'une problématique de découpage complexe. Une fois ces Tokens bruts obtenus, il sera souhaitable de les transformer et/ou de les supprimer du flux (cas des mots-vides). Cette opération est réalisée grâce à des descendants de la classe org.apache.lucene.analysis.TokenFilter qui recevront un TokenStream en entrée, et qui a leur tour, émettront des Tokens, éventuellement à destination d'autres TokenFilters. On obtient donc in fine un flux de Tokens qui vont être transformés en objets org.apache.lucene.index.Term stockés dans les index Lucene. Un objet Term comporte 2 propriétés principales :
A première vue, il semblerait que le passage d'un Token à un Term fasse perdre beaucoup d'information : la position de début dans le flux d'entrée, la position de fin dans le flux d'entrée, le type de Token, ainsi que la position relative par rapport au Token précédent disparaissent. C'est vrai pour les trois premières propriétés, qui n'ont pour but que de récupérer les information fournies par le flux d'entrée et/ou les différents processus de filtrage des Tokens, mais c'est faux pour la dernière : la méthode termPositions() de la classe org.apache.lucene.index.IndexReader est capable de retrouver la position d'un terme et donc de permettre les requêtes de proximité. En effet, pour des raisons de performances, l'architecture de Lucene a préféré mutualiser la position des termes du niveau des index ainsi que l'indique la documentation de la méthode : Returns an enumeration of all the documents which contain term. For each document, in addition to the document number and frequency of the term in that document, a list of all of the ordinal positions of the term in the document is available. Thus, this method implements the mapping: Term => <docNum, freq, <pos1, pos2, ... posfreq-1> >* Pour un terme donné, l'index stocke donc un numéro d'ordre de document, le nombre d'occurences du terme dans le document, ainsi que les différentes positions du terme dans ce document. On peut donc tout à fait légitimement comparer un analyseur d'indexation à un Pipeline Cocoon, le Tokenizer jouant le rôle du générateur, les TokenFilters jouant les rôle des transformateurs et la classe org.apache.lucene.index.IndexWriter jouant le rôle de sérialiseur. Un analyseur de requête, serait, lui, sérialisé vers un objet org.apache.lucene.search.Query composé d'une ou plusieurs requêtes "atomiques" issues du package org.apache.lucene.search La documentation sur la multilinguisme explique clairement la façon de définir un analyseur. Nous allons décrire la façon dont opère l'analyseur français fourni par défaut dans SDX, fr.gouv.culture.sdx.search.lucene.analysis.Analyzer_fr Exmaminons sa methode tokenStream : public final TokenStream tokenStream(String fieldName, Reader reader) { // The token stream that will be returned. TokenStream result; // Builds the chain... result = new StandardTokenizer(reader); FrenchStandardFilter fsf = new FrenchStandardFilter(); fsf.enableLogging(logger); fsf.setUp(result); result = fsf; result = new LowerCaseFilter(result); if (!keepAccents) { ISOLatin1AccentFilter ilf = new ISOLatin1AccentFilter(); ilf.enableLogging(logger); ilf.setUp(result); result = ilf; } if (stopTable != null) result = new StopFilter(result, stopTable); // And returns the end of the chain return result; } La tokenization est assurée par la classe org.apache.lucene.analysis.standard.StandardTokenizer qui renvoie des Tokens typés suivant les constantes définies dans org.apache.lucene.analysis.standard.StandardTokenizerConstants . Tout caractère ne participant pas à la définition d'un Token d'un type reconnu est considéré comme un non-Token remplissant fondamentalement la fonction de séparateur de Tokens. Les Tokens sont ensuite filtrés par fr.gouv.culture.sdx.search.lucene.analysis.filter.FrenchStandardFilter qui supprime les apostrophes et normalise les acronymes en ôtant les points. Le filtre suivant, fr.gouv.culture.sdx.search.lucene.analysis.filter.ISOLatin1AccentFilter , est appelé en fonction de la configuration de l'analyseur. Il a pour rôle d'appauvrir les caractères diacritiques, notamment les caractères accentués, du jeu de caractères ISO-8859-1. Le filtre suivant, org.apache.lucene.analysis.LowerCaseFilter remplace les majuscules par des minuscules. Le dernier filtre, org.apache.lucene.analysis.StopFilter filtre les Tokens qui apparaissent dans une liste de mots vides ; cette liste peut éventuellement être mentionnée dans le fichier de configuration de l'analyseur. L'arabe, comme l'hébreu et certaines autre langues sémitiques anciennes (égyptien, araméen, ougaritique...), n'exprime pas le besoin de noter les voyelles brèves. Quand bien même celles-ci ont une importance fondamentale quand à la catégorisation d'un mot (mode, voie, nombre, sens...), l'écriture attend du lecteur un processus de déduction à partir du contexte, censé lever toute ambiguité entre mots dotés d'un vocalisme différent mais disposant à l'écrit du même squelette consonnantique. |
Auteur : Pierrick Brihaye - 2003-11-22 |