UIMA FR
Communauté francophone autour d'UIMA
  • Accueil
  • Top 10
  • Statistiques
  • Inscription
  • Archives
  • Contact

Informations

UIMA Fr - Agrégation des informations de la communauté francophone autour d'Apache UIMA

Abonnement

  • feed Fil de tous les articles
  • feed Fil des articles populaires

Membres

  • feed  Fabien Poulard
  • feed  Jérôme Rocheteau
  • feed  Matthieu Vernier
  • feed  Nicolas Hernandez
  • feed  Portail UIMA FR

Participer

  • meta Ajouter votre blog
  • meta Administration
Filtrer les articles :     Articles du jour   -   Articles de la semaine   -   Articles du mois   -   Tous les articles

Accès rapide aux derniers articles de la page


14/02/2010 : UIMA & Wikipédia (4) : Analyse de la syntaxe MediaWiki 12/02/2010 : UIMA & Wikipédia (3) : Filtrage des données à charger 07/02/2010 : Scripts de téléchargement et d'installation d'un environnement pour utiliser Apache UIMA (>2.3)... 02/02/2010 : UIMA & Wikipédia (2) : Chargement d'un dump Wikipedia 01/02/2010 : UIMA & Wikipédia (1) : Proposition de Type System 29/01/2010 : Sortie d'Apache UIMA 2.3 28/01/2010 : Comment filtrer des annotations avec UIMA ? 20/01/2010 : Comment récupérer les descripteurs XML de composants UIMA à partir du CLASSPATH ? 14/01/2010 : Comment calculer l'occurrence de termes dans une collection de documents avec UIMA ? 12/01/2010 : Installer les UIMA Addons Annotators & tools
« Page précédentePage suivante »
UIMA & Wikipédia (4) : Analyse de la syntaxe MediaWiki 
0 vote
Par Fabien Poulard le 14/02/2010 à 00:00

Wikipedia est une incroyable source d’information, de données et plus généralement d’actes langagiers (utilisation du langage). Ce dernier point est très important pour nous autres chercheurs en traitement automatique des langues. En effet, nous avons besoin d’observer de très nombreux exemples d’utilisation du langage, que ce soit de manière automatique ou manuelle. Pour ce faire, nous compilons de vastes exemples d’utilisation du langage sous forme de corpus.

La création de composants UIMA permettant d’accéder et tirer parti de Wikipédia offrirait de nouvelles perspectives au traitement des langues en offrant un accès aisé à cette formidable ressource que représente l’encyclopédie libre. Je compte m’atteler à la création de tels composants et vais tâcher de publier plusieurs billets décrivant ma démarche en cours.

Voici le quatrième billet qui discute de l’analyse syntaxique du contenu des pages wiki pour la suppression des balises Wiki.

Analyse syntaxique des pages MediaWiki

Il existe plusieurs initiatives de programmes permettant d’interpréter la syntaxe de MediaWiki. Il y a le code PHP utilisé par MediaWiki et qui sert de référence, mais également plusieurs autres initiatives notamment en Java.

La plupart des initiatives Java ont pour objectif de produire des version XHTML ou PDF des pages en syntaxe wiki et ne donnent pas accès à l’arbre syntaxique de la page. Un programme en C basé sur Flex/Bison et développé dans le cadre du projet MediaWiki offre cette possibilité.

Parmi les initiatives en Java qui semblent intéressantes pour le collection reader UIMA :

  • JAMWiki qui est plus ou moins une réécriture de MediaWiki en Java et dont l’analyseur syntaxique semble réutilisable ;
  • WikiModel supporte plusieurs langages Wiki ;
  • Bliki

J’ai tout d’abord essayé Bliki pour traiter la syntaxe de MediaWiki. Ce dernier s’est toutefois avéré assez complexe, notamment au niveau de son architecture, de telle façon que je n’ai pas réussi à obtenir ce que je voulais. Je me suis alors tourné vers WikiModel qui offre un analyseur syntaxique (Wiki Event Model (WEM)) au fonctionnement proche de SAX.

WikiModel pour MediaWiki

Le gros avantage de WikModel est qu’il offre directement un parseur pour MediaWiki : org.wikimodel.wem.mediawiki.MediaWikiParser. Le parseur analyse du code Wiki brute et, comme un parseur SAX classique, lance des évènements à une instance implémentant l’interface org.wikimodel.wem.IWemListener. J’ai choisi de créer une classe MediawikiCasConverter implémentant cette interface et gérant elle même le lancement du parseur sur les textes brutes extraits des révisions.

  1. import org.wikimodel.wem.mediawiki.MediaWikiParser
  2. import org.wikimodel.wem.IWemListener;
  3. ...
  4. public class MediawikiCasConverter implements IWemListener {
  5.  
  6. public MediawikiCasConverter() {
  7. theParser = new MediaWikiParser();
  8. }
  9.  
  10. public void runParser(String rawWikiText) throws WikiParserException {
  11. // We use a string reader to parse the raw wiki texte
  12. StringReader reader = new StringReader(rawWikiText);
  13. // Parsing
  14. theParser.parse(reader, this);
  15. }
  16.  
  17. // IWemListener methods below
  18. ...
  19. }

Les méthodes du IWemListener sont de deux types. Les premières sont des méthodes one shot, ie elles sont appelées une seule fois lorsqu’un élément est rencontré. Ce sont notamment celles qui concernent le texte et leur mise en forme :

  • onEscape(String str)
  • onSpace(String str)
  • onSpecialSymbol(String str)
  • onWord(String str)
  • onReference(String str)

Les secondes sont des méthodes à la SAX en deux temps : begin et end. Ce sont notamment celles qui concernent la structuration du texte :

  • beginHeader(int headerLevel, WikiParameters params)
  • endHeader(int headerLevel, WikiParameters params)
  • beginSection(int docLevel, int headerLevel, WikiParameters params)
  • endSection(int docLevel, int headerLevel, WikiParameters params)
  • beginParagraph(WikiParameters params)
  • endParagraph(WikiParameters params)
  • beginList(WikiParameters params, boolean ordered)
  • endList(WikiParameters params, boolean ordered)

La plupart de ces méthodes ne font que des appels à une fonction de plus haut niveau qui collecte les données textuelles de la page et qui maintient l’index du CAS : addToContent. C’est notamment le cas pour la méthode onWord qui est appelée lorsque le parseur rencontre un nouveau mot :

  1. /**
  2.  * This method adds the string in parameter into the collected content
  3.  * and then increment the offset by the size of this string.
  4.  *
  5.  * @param str the string to be added to the content
  6.  */
  7. protected void addToContent(String str) {
  8. if ( str != null ) {
  9. theTextContent.append(str);
  10. theOffset += str.length();
  11. }
  12. }
  13. ...
  14. /** Called when a word is encountered */
  15. public void onWord(String str) {
  16. addToContent(str);
  17. }

J’ai choisi de transposer une partie des informations contenues dans les pages de Wikipedia sous la forme d’annotations. J’ai ainsi ajouté les types :

  • Header pour les titres qui possède un attribut Level indiquant le niveau de titre ;
  • Paragraph pour différencier les paragraphes ;
  • Section pour repérer les sections même si je ne suis pas certain d’avoir bien compris le principe de section dans MediaWiki. Ce type possède les attributs Level pour le niveau de section (cf. niveau de titre), Parent pointant sur la section parente et Title pointant sur le Header correspondant à ladite section ;
  • Link pour les liens divers et variés qui possède des attributs Label et Link pour respectivement l’étiquette du lien et son adresse.

En ce qui concerne les liens, j’ai choisi pour le moment d’ignorer les images qui me semblent apporter plus de bruit qu’autre chose.

La mise en place de ces annotations se fait assez facilement :

  1. Lors d’un appel à begin..., l’annotation est créée est stockée dans une liste, la plupart des informations excepté son index de fin est renseigné à ce moment ;
  2. Lors de l’appel correspondant à end..., la dernière annotation de la liste est récupérée et on fixe son index de fin (setEnd) ;
  3. Lorsque l’analyse est terminée, toutes les annotations sont accessibles par la méthode getAnnotations afin de les ajouter à l’index du CAS.

Cette approche permet de dédier toute la partie analyse à une classe. Si jamais l’on veut ignorer certaines annotations (ou toutes), il suffit de les filtrer au moment de leur récupérer par getAnnotations. L’extrait de code ci-dessous illustre ce fonctionnement pour les titres :

  1. /**
  2.  * When we encounter a new header, we create an annotation for it.
  3.  */
  4. public void beginHeader(int headerLevel, WikiParameters params) {
  5. // Jump a line
  6. addToContent("\n\n");
  7. // Create the annotation
  8. Header header = new Header(theCas);
  9. header.setLevel(headerLevel);
  10. header.setBegin( theOffset );
  11. // Add it to the list
  12. theHeadersAnnotations.add( header );
  13. // Add it as header of the last unclosed section
  14. if ( theUnclosedSections.size() > 0 ) {
  15. Section section = theUnclosedSections.get( theUnclosedSections.size()-1 );
  16. section.setTitle(header);
  17. }
  18. }
  19.  
  20. /**
  21.  * Add the ending value of the last started header.
  22.  */
  23. public void endHeader(int headerLevel, WikiParameters params) {
  24. // Retrieve the last header
  25. Header header = theHeadersAnnotations.get( theHeadersAnnotations.size()-1 );
  26. // Update its ending value
  27. header.setEnd( theOffset );
  28. // Jump a line
  29. addToContent("\n\n");
  30. }

Je me suis rendu compte que le parseur posait des problèmes (heap overflow) sur des pages de certains espaces de noms. J’ai donc choisi de n’appliquer l’analyse syntaxique qu’aux pages de l’espace de nom 0 (espace de nom principal). Ceci est toutefois facilement modifiable dans la méthode uima.wikipedia.mwdumper.ThreadedMWDumper.writeStartPage.

Il reste pas mal d’améliorations possibles : prendre en compte toutes les mises en formes/structurations, prendre en charge les macros, rendre l’analyse syntaxique configurable. Toutefois, le composant est dans l’état actuel aussi complet et performant que je le souhaitais à l’origine. Il ne reste plus qu’à le tester de manière intensive. J’ai d’ailleurs deux trois cobayes en tête pour ça.

Nouvelle version du composant

Pas de nouvelle version du composant pour l’instant. Étant donné que les dépendances se sont multipliées, et que le composant est désormais suffisamment fonctionnel pour se voir estampillé 1.0 ou quelque chose du genre, je vais travailler un peu plus son packaging.

Autres articles

  • UIMA & Wikipédia (1) : Proposition de Type System
  • UIMA & Wikipédia (2) : Chargement d’un dump Wikipedia
  • UIMA & Wikipédia (3) : Filtrage des données à charger
  • UIMA & Wikipédia (5) : Gestion du projet avec Maven
Retour au sommaire
UIMA & Wikipédia (3) : Filtrage des données à charger 
0 vote
Par Fabien Poulard le 12/02/2010 à 00:00

Wikipedia est une incroyable source d’information, de données et plus généralement d’actes langagiers (utilisation du langage). Ce dernier point est très important pour nous autres chercheurs en traitement automatique des langues. En effet, nous avons besoin d’observer de très nombreux exemples d’utilisation du langage, que ce soit de manière automatique ou manuelle. Pour ce faire, nous compilons de vastes exemples d’utilisation du langage sous forme de corpus.

La création de composants UIMA permettant d’accéder et tirer parti de Wikipédia offrirait de nouvelles perspectives au traitement des langues en offrant un accès aisé à cette formidable ressource que représente l’encyclopédie libre. Je compte m’atteler à la création de tels composants et vais tâcher de publier plusieurs billets décrivant ma démarche en cours.

Voici le troisième billet qui discute du filtrage des données à charger : articles, révision, ...

Filtres de MWDumper

L’outil mwdumper inclut un certain nombre de filtres commandables à partir de la ligne de commande :

  • LatestFilter permet de ne conserver que la dernière révision d’une page ;
  • NamespaceFilter permet de ne conserver que les articles qui appartiennent à un espace de nom particulier (passé en paramètre) ;
  • NotalkFilter permet d’ignorer les pages de discussion ;
  • TitleMatchFilter permet de ne conserver que les pages dont le titre valide une expression rationnelle donnée en paramètre ;
  • ListFilter permet de ne conserver que les pages dont le titre de la page de données ou de discussion est présent dans un fichier passé en paramètre (un nom de page par ligne) ;
  • ExactListFilter est identique au filtre précédent si ce n’est que son application est plus stricte car seul le titre de la page est considéré ;
  • RevisionListFilter reprend le principe des filtres précédents si ce n’est qu’il s’applique aux identifiants de révisions ;
  • BeforeTimeStampFilter ne conserve que les données produites avant une date passée en paramètre ;
  • AfterTimeStampFilter ne conserve que les données produites après une date passée en paramètre ;

Voir le billet Insérer plusieurs copies locales de Wikipedia dans une base PostgreSQL pour un cas d’utilisation de ces filtres. La combinaison de ces filtres permet de contrôler avec précision les données à charger, nous allons donc nous en contenter.

Paramétrage du composant

On peut classer les filtres en deux familles : ceux qui nécessitent des paramètres et ceux qui n’en nécessitent pas. J’ai donc choisi pour le moment d’utiliser des paramètres booléens pour les filtres sans paramètre, et des paramètres chaînes de caractères pour les autres.

L’activation des paramètres booléens suffit à activer les filtres correspondant : IgnoreTalks et LatestRevisionOnly.

Pour activer les autres filtres il suffit de les configurer en renseignant les champs dédiés. Si les champs restent non renseignés alors les filtres ne sont pas activés : ConfigNamespacesFilter, ConfigTitleMatch, ConfigListFilter, ConfigExactListFilter, ConfigRevisionListFilter, ConfigBeforeTimestampFilter, ConfigAfterTimestampFilter.

Nouvelle version

Voici une nouvelle version du collection reader pour Wikipédia, estampillée 0.2, qui ne prend toujours pas en compte la syntaxe, mais qui permet de filtrer le type de contenu à charger à partir du dump XML. Pour utiliser le composant, il est nécessaire d’avoir le jar de mwdumper dans le classpath.

Autres articles

  • UIMA & Wikipédia (1) : Proposition de Type System
  • UIMA & Wikipédia (2) : Chargement d’un dump Wikipedia
  • UIMA & Wikipédia (4) : Analyse de la syntaxe MediaWiki
  • UIMA & Wikipédia (5) : Gestion du projet avec Maven
Retour au sommaire
Scripts de téléchargement et d'installation d'un environnement pour utiliser Apache UIMA (>2.3) et développer avec sous Eclipse 
0 vote
Par Nicolas Hernandez le 07/02/2010 à 23:58
Afin de me faciliter la vie, ainsi celles de mes étudiants, j'ai mis en place un environnement qui regroupe tous les pré-requis pour  utiliser Apache UIMA et développer avec sous Eclipse.

FEATURES
  • Scripts pour assister le téléchargement et l'installation d'un environnement pour utiliser Apache UIMA et développer avec sous Eclipse. 
  • La configuration est centralisée pour faciliter la prise en compte les futures mise à jour des outils requis pour l'environnement
  • Ces outils requis sont Java JDK Sun, Eclipse, plugins eclipse (UIMA, Subversion et Maven), Apache UIMA (UIMAJ, UIMA-AS, UIMACPP, Addons), Apache tomcat, OpenNLP, maven, ant, subversion 
  • Les scripts sont distribués sous licence GPLv3 (liberté de modifier et redistribuer le travail, redistribution des travaux dérivés sous la même licence, mise à disposition du code source) 
  • Testés sous Ubuntu 8.10 - Hardy et 9.04 - Jaunty Jackalope
VERSION

La version datée du 7/02/2010 intègre les versions suivantes des outils 
  • Java Sun Development Kit  (jdk-6u17-linux-i586)
  • Eclipse Galileo (3.5)
  • Plugins UIMA,  subversion subeclipse,  maven m2eclipse        
  • Apache UIMA 2.3.0-incubating
  • OpenNLP v1.3
  • Apache Tomcat 6.0.20
TELECHARGEMENT
Télécharger ici les scripts d'installation d'un environnement d'utilisation et développement Apache UIMA
Retour au sommaire
UIMA & Wikipédia (2) : Chargement d'un dump Wikipedia 
0 vote
Par Fabien Poulard le 02/02/2010 à 00:00

Wikipedia est une incroyable source d’information, de données et plus généralement d’actes langagiers (utilisation du langage). Ce dernier point est très important pour nous autres chercheurs en traitement automatique des langues. En effet, nous avons besoin d’observer de très nombreux exemples d’utilisation du langage, que ce soit de manière automatique ou manuelle. Pour ce faire, nous compilons de vastes exemples d’utilisation du langage sous forme de corpus.

La création de composants UIMA permettant d’accéder et tirer parti de Wikipédia offrirait de nouvelles perspectives au traitement des langues en offrant un accès aisé à cette formidable ressource que représente l’encyclopédie libre. Je compte m’atteler à la création de tels composants et vais tâcher de publier plusieurs billets décrivant ma démarche en cours.

Voici le second billet qui discute du chargement d’un dump XML de l’encyclopédie libre et la distribution du contenu sous forme de CAS.

Wikipédia, formats brutes

La base de données contenant toutes les pages de Wikipédia et autre sites de la fondation WikiMedia est automatiquement archivée très régulièrement. Les dumps de la base sont disponibles sur http://download.wikimedia.org/. Vous trouverez ainsi :

  • les archives de la Wikipédia française
  • les archives de WikiNews ou juste la partie en français
  • les archives de la Wikiversity ou juste la partie en français
  • les archives des WikiBooks

Il est également possible de télécharger l’intégralité de l’encyclopédie dépourvue des balises wiki : http://download.wikimedia.org/nowiki/.

Le billet Créer un miroir Wikipédia explique comment construire une copie locale de l’encyclopédie à partir de ces différents dumps. Nous nous donnons comme objectif d’exploiter ces dumps directement sans passer par une importation en base de données.

L’outil d’exportation et d’importation de MediaWiki : mwdump

MWDumper est un outil écrit en Java par les développeurs de MediaWiki qui permet d’importer/exporter une base MediaWiki à partir de/vers une base de données. Cet outil a l’avantage de travailler directement sur la version compressée du dump XML, réduisant ainsi le besoin en espace disque disponible. Cet outil s’utilise en ligne de commande et offre un certain nombre de paramètres permettant notamment de filtrer les articles à exporter ou bien le format SQL à prendre en charge.

Une version compilée de l’outil est disponible sur download.wikipedia.org, mais il y a de forte chance qu’elle soit dépassée. Le plus sûr est de compiler l’outil depuis les sources.

Une partie du code de cet outil va nous faciliter la tâche pour la réalisation d’un collection reader pour UIMA, notamment les classes :

  • org.mediawiki.importer.XmlDumpReader
  • org.mediawiki.importer.DumpWriter
  • org.mediawiki.importer.Page
  • org.mediawiki.importer.Revision

Il nous faut toutefois noter que XmlDumpReader repose sur un analyseur SAX, ce qui n’est pas directement utilisable dans un Collection Reader d’UIMA. En effet, dans UIMA c’est le Collection Reader qui contrôle l’exécution, alors qu’à l’opposé l’analyseur SAX contrôle sa propre exécution. La seule interaction avec le parseur est l’emploi des hooks.

L’idée est de faire tourner l’analyseur SAX dans un thread différent de celui du collection reader. Ensuite à l’aide d’un mécanisme de sémaphore (ou de monitor en Java), on contrôle l’exécution du parseur pour produire les CAS. Cette méthode permet d’utiliser presque directement l’outil de MediaWiki, ainsi si la syntaxe évolue, l’outil de MediaWiki évoluera également certainement et ce sera donc normalement transparent pour le collection reader.

Une première version de collection reader pour Wikipedia

Voici une première version du collection reader pour Wikipédia qui ne prend pas du tout en compte la syntaxe, mais charge seulement le contenu des pages dans un CAS. Il y a encore beaucoup de travail pour obtenir quelque chose d’intéressant et d’utilisable, d’où l’estampillage 0.1. Pour utiliser le composant, il est nécessaire d’avoir le jar de mwdumper dans le classpath.

Il y a tout un tas d’améliorations que j’aimerais apporter (filtrage, analyse de la syntaxe wiki, ...) mais l’idée est dans un premier temps de fournir une version brute de fonderie qui fonctionne pour qu’elle puisse être testée. Le jar contient notamment le code Java, donc il ne faut pas hésiter à y jeter un oeil.

Le descripteur est dans le Jar distribué, il ne prend en paramètre que le chemin vers le dump XML à charger. Peu importe l’extension (.gz, .bz, ...), il devrait pouvoir s’en sortir. Si ce n’est pas le cas, laissez un commentaire ! Je n’ai fait que peu de tests pour le moment, je ne sais pas trop comment le composant tient la route sur des gros dumps, mais la première remarque est qu’il est nécessaire d’augmenter la taille du tas de la jvm (-Xmx=512m pour commencer). En effet, certaines pages sont assez imposantes de par leur grand nombre de révisions, et pour l’instant toutes les révisions sont chargées dans chaque CAS.

Autres billets

  • UIMA & Wikipédia (1) : Proposition de Type System
  • UIMA & Wikipédia (3) : Filtrage des données à charger
  • UIMA & Wikipédia (4) : Analyse de la syntaxe MediaWiki
  • UIMA & Wikipédia (5) : Gestion du projet avec Maven
Retour au sommaire
UIMA & Wikipédia (1) : Proposition de Type System 
0 vote
Par Fabien Poulard le 01/02/2010 à 00:00

Wikipedia est une incroyable source d’information, de données et plus généralement d’actes langagiers (utilisation du langage). Ce dernier point est très important pour nous autres chercheurs en traitement automatique des langues. En effet, nous avons besoin d’observer de très nombreux exemples d’utilisation du langage, que ce soit de manière automatique ou manuelle. Pour ce faire, nous compilons de vastes exemples d’utilisation du langage sous forme de corpus.

La création de composants UIMA permettant d’accéder et tirer parti de Wikipédia offrirait de nouvelles perspectives au traitement des langues en offrant un accès aisé à cette formidable ressource que représente l’encyclopédie libre. Je compte m’atteler à la création de tels composants et vais tâcher de publier plusieurs billets décrivant ma démarche en cours.

Voici le premier billet qui discute de la création d’un Type System approprié pour représenter les pages de Wikipedia.

Wikipédia, structuration des données

L’encyclopédie Wikipédia contient tout un tas d’informations mais je me concentrerai particulièrement sur le contenu même : les articles. Je propose de classer les informations concernant ces derniers en quatre grandes catégories :

  • Position de l’article dans l’encyclopédie (portail, catégories, ...)
  • Versions de l’article (révisions, ...)
  • Structuration de l’article (titre, sous-titre, ...)
  • Macros et mise en forme du texte (gras, italique, ...)

Position de l’article dans l’encyclopédie

On peut considérer la Wikipédia comme un ensemble de pages liées selon trois grandes relations :

  • Les catégories
  • Les liens interlangues
  • Les liens internes

Les catégories structurent l’encyclopédie à la manière d’une ontologie ou d’un thésaurus. Une page peut appartenir à une ou plusieurs catégories. De plus, les catégories sont hiérarchisées, l’appartenance à une catégorie implique l’appartenance à toutes les catégories parentes.

Les liens interlangues marquent les pages en relation de traduction avec la page courante.

Les liens internes permettent au sein d’une page de faire référence à d’autres pages de l’encyclopédie, il s’agit d’une structuration qui n’a qu’un impact local. La signification de ces références est très variable et difficilement identifiable.

Versions de l’article

Le principe de l’encyclopédie collaborative est que tout le monde peut modifier un article, ce qui amène à de multiples révisions de ces derniers. Lorsque vous cliquez sur l’onglet Historique d’un article, vous pouvez visionner ces différentes révisions, leur auteur, et éventuellement un commentaire précisant l’apport de la révision.

Structuration d’un article

Le contenu d’un article se structure à l’aide de titres, de paragraphes ainsi que de divers éléments de mise en forme : [tableaux], [formules], [listes], ...

Parmi les éléments de mise en forme, on peut également noter l’existence de plusieurs macros pour les [modèles], [dates], [liens interwiki], ...

Choix d’un Type System

Je ne crois personnellement pas à l’existence de Type Systems génériques pouvant être partagés par tous les composants. De mon point de vue, un Type System va être approprié au traitement d’une tâche particulière, chercher à en produire un suffisamment générique pour toutes les tâches seraient une perte de temps et mènerait certainement à un TS difficile à utiliser.

Personnellement, je vais utiliser Wikipedia dans le cadre de ma thèse sur la détection de dérivation de texte. Ce qui m’intéresse c’est donc de générer un CAS par article dans lequel on retrouvera les différentes révisions dudit article. Je m’intéresse donc :

  • à la notion d’article
  • aux notions de révision
  • à la structuration du contenu d’un article à l’aide des titres et des paragraphes
  • au texte

Après réflexion j’en suis donc arrivé à cette modélisation :

TS Wikipedia (png)

Cette modélisation ne correspond pas exactement aux besoins d’un TS UIMA. Ainsi, les relations de composition se manifestent par un phénomène de couverture des annotations, entraînant la disparition des attributs correspondant.

Vous trouverez le descripteurs correspondant à ce TS ici.

Autres billets

  • UIMA & Wikipédia (2) : Chargement d’un dump Wikipedia
  • UIMA & Wikipédia (3) : Filtrage des données à charger
  • UIMA & Wikipédia (4) : Analyse de la syntaxe MediaWiki
  • UIMA & Wikipédia (5) : Gestion du projet avec Maven
Retour au sommaire
Sortie d'Apache UIMA 2.3 
0 vote
Par Fabien Poulard le 29/01/2010 à 00:00

L’annonce est parue hier sur les listes concernées, la nouvelle version du framework Apache UIMA (Unstructured Information Management Architecture) est sortie, estampillée 2.3 !

Au programme de cette nouvelle version, beaucoup de corrections de bug come d’habitude, mais surtout l’intégration de UIMA-AS qui permet une meilleure distribution des calculs entre plusieurs serveurs et l’ajout de plusieurs addons :

  • Bean Scripting Framework qui va permettre d’écrire des annotateurs dans plusieurs langages de script ;
  • Lucas qui permet d’interfacer UIMA avec Apache Lucene
  • TikaAnnotator qui fait également parti du projet Apache Lucene et qui permet tout simplement de charger un grand nombre de formats de fichiers (html, xml, Microsoft Office, pdf, rtf ainsi que des formats audio et vidéo).

Cette nouvelle mouture d’UIMA tire désormais parti des génériques de Java 5, ce qui va permettre de limiter les casting aventureux pour récupérer les annotations, itérateurs, ... :) Cela signifie toutefois que la version 5 de Java est désormais le requis minimum pour utiliser UIMA.

Vous trouverez plus de détails sur cette version dans les notes de release :

  • UIMA Java
  • UIMA AS
  • UIMA C++
  • Addons
Retour au sommaire
Comment filtrer des annotations avec UIMA ? 
0 vote
Par Jérôme Rocheteau le 28/01/2010 à 12:04

Ce billet explique comment sélectionner des annotations en appliquant des filtres sur les indexes des CASes. On prend l'exemple d'un Analysis Engine qui filtre le mot « saperlipopette » dans des textes.

La plate-forme UIMA offre des facilités pour filtrer les annotations parmi l'index d'un CAS. J'explique rapidement comment faire fonctionner ce mécanisme de filtrage en trois temps :

  1. Tout d'abord, il s'agit de récupérer le type d'annotations que nous voulons sélectionner.
  2. Ensuite, il s'agit de sélectionner parmi les annotations seulement celles qui correspondent à ce type.
  3. Enfin, il s'agit d'appliquer un filtre sur ces annotations sélectionnées. Ce filtre est défini par une contrainte qui correspond à ce que nous voulons sélectionner.

La partie générique du code ci-dessous correspond à la façon de créer des contraintes qui permettront d'appliquer des filtres sur les annotations. Il s'agit de créer des contraintes sur la valeur de certains traits d'annotations. Une contrainte peut-être vue avec UIMA comme la donnée d'un chemin de traits (feature path) et d'une contrainte de base (contrainte numérique entière, contrainte numérique flottante, contrainte textuelle, etc). Le mécanisme interne à UIMA consiste vérifier si la valeur du chemin de traits de chaque annotation sélectionnée satisfait effectivement la relation définie par la contrainte de base. C'est ce que fait la méthode getConstraint dans la classe ci-dessous.

La méthode getBasicConstraint renvoie la contrainte de base en fonction de la valeur et plus précisément de son type. Cette méthode s'appuie alors sur deux méthodes getIntContraint et getStringConstraint qui renvoie la contrainte de base en fonction de la relation voulue entre le chemin de traits et la valeur précédente, à savoir une relation d'égalité ou d'inégalité.

En outre, l'Analysis Engine ci-dessous définit une méthode getType qui renvoie le type à partir de son nom et une méthode getFeaturePath qui renvoie le chemin de traits correspondant au type d'annotation et au nom de ce trait.

L'Analysis Engine Filtering suivant réalise les opérations décrites ci-dessus et les met en œuvre afin d'afficher les mots « saperlipopette ». On suppose ainsi que le Type System de cet Analysis Engine contient un type d'annotation fr.free.rocheteau.jerome.Mot qui possède un trait value correspondant au texte couvert par ces mots.

public class Filtering extends JCasAnnotator_ImplBase {

private Type getType (JCas cas,String name) {
Type type = cas.getTypeSystem().getType(name);
if (type == null) {
type = cas.getTypeSystem().getType(name);
if (type == null) {
type = cas.getTypeSystem().getType(name);
if (type == null) {
String msg = "Unknown type " + name);
System.out.println(msg);
}
}
}
return type;
}

private FeaturePath getFeaturePath(JCas cas,Type type,String feat) {
Feature feature = type.getFeatureByBaseName(feat);
FeaturePath path = cas.createFeaturePath();
path.addFeature(feature);
return path;
}

private int EQ = 0;

private int LT = 1;

private int LEQ = 2;

private int GEQ = 3;

private int GT = 4;

private FSConstraint getStringConstraint(ConstraintFactory factory,int type,String string) {
FSStringConstraint constraint = factory.createStringConstraint();
if (type == this.EQ) {
constraint.equals(string);
} else {
return null;
}
return constraint;
}

private FSConstraint getIntConstraint(ConstraintFactory factory,int type,Integer integer) {
FSIntConstraint constraint = factory.createIntConstraint();
if (type == this.EQ) {
constraint.eq(integer);
} else if (type == this.LT) {
constraint.lt(integer);
} else if (type == this.LEQ) {
constraint.leq(integer);
} else if (type == this.GT) {
constraint.gt(integer);
} else if (type == this.GEQ) {
constraint.geq(integer);
} else {
return null;
}
return constraint;
}

private FSConstraint getBasicConstraint(ConstraintFactory factory,int type,Object value) {
if (value instanceof java.lang.String) {
return this.getStringConstraint(factory, type,(String) value);
} else if (value instanceof java.lang.Integer) {
return this.getIntConstraint(factory,type,(Integer) value);
} else {
return null;
}
}

private FSMatchConstraint getConstraint(JCas cas,Type type,String feat,int typ,Object value) {
ConstraintFactory factory = cas.getConstraintFactory();
FSConstraint constraint = this.getBasicConstraint(factory,typ,value);
FeaturePath path = this.getFeaturePath(cas,type,feat);
FSMatchConstraint filter = factory.embedConstraint(path,constraint);
return filter;
}

public void initialize(UimaContext context) throws ResourceInitializationException {
}

public void process(JCas cas) throws AnalysisEngineProcessException {
Type type = this.getType(cas,"fr.free.rocheteau.jerome.Mot");
FSMatchConstraint filter = this.getConstraint(cas,type,"value",this.EQ,"saperlipopette");
FSIterator iter = cas.getAnnotationIndex(type).iterator();
FSIterator res = cas.createFilteredIterator(iter,filter);
while (res.hasNext()) {
Annotation a = res.next();
System.out.println(a.toString(2));
}
}

}
Retour au sommaire
Comment récupérer les descripteurs XML de composants UIMA à partir du CLASSPATH ? 
0 vote
Par Jérôme Rocheteau le 20/01/2010 à 11:36

Ce billet explique comment récupérer les descripteurs XML de Type Systems, Collection Readers, d'Analysis Engines, de CAS Consumers ou d'autres descripteurs XML pour des composants UIMA à partir de répertoires ou d'archives JAR contenus dans le CLASSPATH d'une application Java.

Les outils pour UIMA requiert pour l'instant que les descripteurs XML des composants se trouvent sur le système de fichiers local. Dans la terminologie UIMA, cela s'appelle « importer un composant par son emplacement » (import by location). Or, la plate-forme UIMA permet également de récupérer des composants par leur nom s'ils sont contenus dans le CLASSPATH (import by name). Malheureusement les outils UIMA ne fournissent pas (encore) cette fonctionnalité. Je propose une solution qui s'effectue en deux temps.

Tout d'abord, il s'agit récupérer la liste des éléments contenus dans le CLASSPATH, à parcourir ces éléments et à sélectionner les fichiers XML qu'ils contiennent. Seuls deux types d'élements sont traités : les archives JAR et les répertoires sur le système de fichiers local. C'est la fonction de la méthode setFiles dans l'exemple ci-dessous. Cette méthode fait appel aux deux méthodes addFile pour construire la liste des fichiers XML contenus dans les éléments du CLASSPATH.

Ensuite, il s'agit de parcourir cette liste de fichiers XML et de construire un descripteur XML d'un Analysis Engine à partir des méthodes fournies par la plate-forme UIMA. Si on réussit à obtenir un tel descripteur, on l'ajoute à la liste des Analysis Engines disponibles dans le CLASSPATH. Sinon on tente de construire un descripteur XML d'un Collection Reader qui est lui-même ajouté à la liste des Collection readers disponibles dans le CLASSPATH. C'est le rôle de la méthode setComponents dans l'exemple ci-dessous qui fait appel aux méthodes addAnalysisEngine et addCollectionReader. On a commencé par les Analysis Engines étant donné qu'il représente la majorité des descripteurs XML pour UIMA. On pourrait imaginer étendre la méthode setComponents pour détecter les Type Systems, les CAS Consumers et les autres types de composants UIMA.

public class ComponentDetection {

private List collectionReaders;

private void setCollectionReaders() {
this.collectionReaders = new ArrayList();
}

private List getCollectionReaders() {
return this.collectionReaders;
}

private void addCollectionReader(String name) throws IOException, InvalidXMLException {
XMLInputSource source = new XMLInputSource(name);
XMLParser parser = UIMAFramework.getXMLParser();
CollectionReaderDescription desc = parser.parseCollectionReaderDescription(source);
this.getCollectionReaders().add(desc);
}

private List analysisEngines;

private void setAnalysisEngines() {
this.analysisEngines = new ArrayList();
}

private List getAnalysisEngines() {
return this.analysisEngines;
}

private void addAnalysisEngine(String name) throws IOException, InvalidXMLException {
XMLInputSource source = new XMLInputSource(name);
XMLParser parser = UIMAFramework.getXMLParser();
AnalysisEngineDescription desc = parser.parseAnalysisEngineDescription(source);
this.getAnalysisEngines().add(desc);
}

private List files;

private void setFiles() {
this.files = new ArrayList();
String classPath = System.getProperty("java.class.path");
String pathSeparator = System.getProperty("path.separator");
String[] pathElements = classPath.split(pathSeparator);
for (String pathElement : pathElements) {
try {
JarFile jarFile = new JarFile(pathElement);
this.addFile(jarFile);
} catch (IOException e) {
File file = new File(pathElement);
if (file.exists()) {
if (file.isDirectory()) {
addFile(file);
}
}
} catch (SecurityException e) {
System.err.println(e.getMessage());
}
}
}

private List getFiles() {
return this.files;
}

private void addFile(JarFile jar) {
Enumeration entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.isDirectory()) {
String name = entry.getName();
if (name.endsWith(".xml")) {
try {
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL url = cl.getResource(name);
URI uri = url.toURI();
files.add(uri);
} catch (URISyntaxException e) {
System.err.println(e.getMessage());
}
}
}
}
}

private void addFile(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
addFile(f);
}
} else {
String name = file.getName();
if (name.endsWith(".xml")) {
try {
URI uri = new URI(file.getAbsolutePath());
files.add(uri);
} catch (URISyntaxException e) {
System.err.println(e.getMessage());
}
}
}
}

private void setComponents() {
this.setAnalysisEngines();
this.setCollectionReaders();
for (URI file : this.getFiles()) {
String name = file.toString();
try {
this.addAnalysisEngine(name);
} catch (Exception e) {
try {
this.addCollectionReader(name);
} catch (Exception ee) { }
}
}
}

public ComponentDetection() {
this.setFiles();
this.setComponents();
}

}
<:pre>
Retour au sommaire
Comment calculer l'occurrence de termes dans une collection de documents avec UIMA ? 
0 vote
Par Jérôme Rocheteau le 14/01/2010 à 12:11

Ce billet explique comment réaliser un Analysis Engine qui calcule les occurrences des termes dans des documents avec UIMA et qui les affiche à la fin du traitement de la collection.

Nous définissons tout d'abord ce qu'est une occurrence avant de réaliser le composant qui calcule l'occurrence des termes dans un document.

Définition des occurrences d'un terme dans un document

Le nombre d'occurrences d'un terme dans un document se caractérise simplement par :
  • par le terme lui-même,
  • par l'identifiant du document,
  • par le nombre de ses occurrences.

La classe Java qui correspond à cette définition se nomme Occurence. Elle possède :

  1. un constructeur Occurence qui prend comme paramètres l'identifiant du document, le terme et qui définit le nombre d'occurences à 1,
  2. une méthode incr qui incrémente le nombre d'occurrences et retourne le booléen true si et seulement si le terme et l'identifiant du document en paramètres sont les mêmes que ceux de la classe
  3. une méthode toString afin d'afficher le résultat.
  4. et une méthode compareTo afin d'ordonner une liste d'objets de type Occurence.

Le code de cette classe Java est le suivant :

private class Occurence implements Comparable {

private int id;
private String term;
private int occ;

public Occurence(int id,String term){
this.id = id;
this.term = term;
this.occ = 1;
}

public boolean incr(int id,String term) {
if (this.id == id && this.term.equals(term)) {
this.occ++;
return true;
} else {
return false;
}
}

public String toString() {
String string = "The term '" + this.term + "'";
string += " has " + this.occ + " occurences";
string += " in the " + this.id + "-th document.";
return string;
}

public int compareTo(Occurence occ) {
int diff = 0;
String fst, snd;
Integer i,j;
i = this.id;
j = occ.id;
diff = i.compareTo(j);
if (diff == 0) {
fst = this.term;
snd = occ.term;
diff = fst.compareTo(snd);
if (diff == 0) {
i = this.occ;
j = occ.occ;
diff = i.compareTo(j);
return -diff;
} else { return diff; }
} else { return diff; }
}

}

Le calcul d'occurrences de termes dans les documents d'une collection

L'Analysis Engine qui calcule les occurrences de termes dans un document possède deux attributs :

  1. le premier num qui correspond à l'identifiant du document de la collection en cours d'analyse,
  2. le second occurences qui correspond à la liste globale des occurrences des termes dans les documents de la collection.

Elle possède une méthode add qui incrémente le nombre d'occurrences d'un terme dans un document si celui-ci existe ou qui ajoute une occurrence de ce terme dans ce document à la liste globale.

L'initialisation de l'Analysis Engine, à l'aide de la méthode initialize, consiste à définir le nombre de document traités à 0 et de créer une liste vide pour les occurrences de termes dans les documents. Cette liste sera persistante au cours de l'analyse complète de la collection !

Le cœur de l'analyse, à l'aide de la méthode process, consiste, pour chaque document, à parcourir les annotations dont le type correspond aux termes souhaités (dans l'exemple ci-dessous il s'agit de mots caractérisés par le type d'annotation Mot) et à ajouter cette occurrence avec le texte couvert par cette annotation et l'identifiant du document en cours d'analyse.

Lorsque l'ensemble des documents de la collection est traitée, cet Analysis Engine affiche alors, à l'aide de la méthode collectionProcessComplete, les occurrences des termes dans les documents (d'où l'utilité de la méthode toString de la class Occurence) à partir de la liste globale triée (d'où la nécessité de la méthode compareTo de la classe Occurence).

La classe Java de cet Analysis Engine est le suivant :

public class OccurenceAnalyser extends JCasAnnotator_ImplBase {

private int num;

private List occurences;

private void add(int num,String term) {
boolean done = false;
for (Occurence occ : this.occurences) {
done = done || occ.incr(num,term);
}
if (!done) {
Occurence occ = new Occurence(num,term);
this.occurences.add(occ);
}
}

public void initialize(UimaContext context) throws ResourceInitializationException {
this.num = 0;
this.occurences = new ArrayList();
}

public void process(JCas cas) throws AnalysisEngineProcessException {
this.num++;
Type type = cas.getTypeSystem().getType("fr.free.rocheteau.jerome.Mot");
FSIterator iter = cas.getAnnotationIndex(type).iterator();
while (iter.hasNext()) {
Annotation annotation = iter.next();
String term = annotation.getCoveredText();
this.add(num,term);
}
}

public void collectionProcessComplete() throws AnalysisEngineProcessException {
Collections.sort(this.occurences);
for (Occurence occ : this.occurences) {
System.out.println(occ);
}
}

}
Retour au sommaire
Installer les UIMA Addons Annotators & tools 
0 vote
Par Nicolas Hernandez le 12/01/2010 à 23:16
Update 20100212: Validé pour Apache UIMA Version 2.2.2-incubating Binary sous linux et Version 2.3.0-incubating
INSTALLATION
Rien de plus simple pour installer les UIMA Annotator Addons and tools

1. Récupérer l'archive addons (celles ci contient tout ce qui est annoncé dans le titre) disponible sur http://incubator.apache.org/uima/downloads.cgi
export UIMAADDONSDISTANTDIR=uimaj-annotator-addons-2.3.0-incubating
export UIMAADDONSARCHIVEFILE=uimaj-annotator-addons-2.3.0-incubating-bin.zip
wget "http://mirror.mkhelif.fr/apache/incubator/uima/binaries/${UIMAADDONSDISTANTDIR}/${UIMAADDONSARCHIVEFILE}"
2. Puis l'installer en la désarchivant dans votre le répertoire parent de votre UIMA_HOME car l'archive contient le répertoire apache-uima qui contient le répertoire addons. De cette manière addons se retrouvera dans votre apache-uima.
unzip "${UIMAADDONSARCHIVEFILE}" -d "$UIMA_HOME/.."
CONFIGURATIONS

Apache UIMAJ Version 2.2.2-incubating contient

  • les annotators suivant  DictionaryAnnotator, RegularExpressionAnnotator, Tagger, WhitespaceTokenizer dans apache-uima/addons/annotator 
  • les outils suivant SimpleServer, PearPackagingAntTask, PearPackagingMavenPlugin dans apache-uima/addons
Apache UIMAJ Version 2.3.0-incubating contient

  • les annotators suivant BSFAnnotator, Lucas, Tagger, ConceptMapper, OpenCalaisAnnotator, TikaAnnotator, ConfigurableFeatureExtractor, RegularExpressionAnnotator  WhitespaceTokenizer, DictionaryAnnotator, SnowballAnnotator dans apache-uima/addons/annotator 
  • les outils suivant SimpleServer, FsVariables PearPackagingAntTask dans apache-uima/addons
Retour au sommaire
« Page précédentePage suivante »
Produit par le BilboPlanet CSS - Xhtml valide Dessiné par le BilboPlanet Retour au début