01avr. 2010
Parcours des annotations couvertes par une autre annotation
11:11 - Par Fabien Poulard - Sciences & Recherche - aucun commentaire
Lorsque l'on travaille avec Apache UIMA et que l'on ajoute un nombre important d'annotations, il arrive un moment où l'on va vouloir filtrer certaines de ces annotations en fonction d'autres. Ainsi, assez couramment on éprouve le besoin de devoir récupérer des annotations qui couvrent la même zone de texte qu'une autre. Par exemple :
- récupérer les mots contenus dans une phrases ;
- récupérer les paragraphes dans un document ;
- …
Il y a au moins deux approches dans Apache UIMA qui permettent de répondre à ce besoin : le subiterator et le FSMatchConstraint.
Utilisation du subiterator
L'approche basée sur le subiterator ne peut fonctionner que si les types que l'on cherche à accéder sont couverts par le type couvrant au sens de UIMA, c-à-d en terme de priorité des types (cf. [la javadoc de TypePriorities] ou cet email).
Considérons une annotation A qui couvre des annotations B de la manière suivante :
Il y a du texte et les annotations sont sur ce texte ... [-----A:1-----] [---A:2---] [--------A:3--------] [B:1] [B:2] [B:3] [B:4] [B:5] [B:6]
Dans l'exemple ci-dessus, nous sommes intéressés par les annotations B couvertes par l'annotation A:3, en d'autres termes les annotations B:4, B:5 et B:6.
La méthode est la suivante :
- On récupère un pointeur sur l'annotation couvrante qui nous intéresse (A:3), à l'aide d'un itérateur par exemple ;
- On récupére l'index des annotations couvertes (les B) ;
- On appelle la méthode subiterator de l'index des annotations couvertes (B) en passant en paramètre l'annotation couvrante (A:3), la méthode nous retourne un itérateur sur les annotations B couvertes par A:3, soit B:4, B:5 et B:6.
Voici le code correspondant :
// Récupération des index AnnotationIndex annAIdx = (AnnotationIndex) jcas.getAnnotationIndex(A.type); AnnotationIndex annBIdx = (AnnotationIndex) jcas.getAnnotationIndex(B.type); // On recherche ''A:3'' FSIterator annAIt = annAIdx.iterator(); while (annAIt.hasNext()) { A monA3 = (A) annAIt.next(); // On récupére l'itérateur sur les annotations B couvertes par A3 FSIterator annBSousA3It = annBIdx.subiterator(monA3); while (annBSousA3It.hasNext()) { // On récupére successivement B4, B5 et B6 B annB = (B) annBSousA3It.next(); System.out.println("Sous A3 : "+annB); } }
Utilisation des contraintes (FSMatchConstraint)
Lorsque l'on ne connaît pas les priorités des types ou bien qu'elles ne correspondent pas à ce que l'on souhaite faire, il est nécessaire de passer par un mécanisme plus complexe (mais beaucoup plus puissant) : le système de contraintes d'index.
Dans le cas présent, nous allons définir une contrainte imposant que les attributs begin et end d'une annotation d'un type donné correspondent à une certaine valeur : celle de l'annotation couvrante. Puis nous pourrons générer un itérateur qui retournera les annotations de l'index qui respectent cette contrainte.
Voici l'implémentation d'une méthode qui fait cela :
/** * * This method provides an iterator over typed annotations that either * have an offset embedded in that of a given annotation in a document, * or have the same offset as these annotation. * * @param theDocument the document in which stand the source and * target annotations * @param theAnnotation the source annotation under which target * annotations that have to be drawn out * @param theType the type of the target annotations that have * to be drawn out from the document under * the source annotation * @param isStrict the boolean that defines the offset matching, * offsets strictly equal if isStrict is true, begin * offsets greater or equal and end offsets less * or equal otherwise. * @return the iterator over the type theType annotations * which stand under the annotation theAnnotation * in the document theDocument * * @author Fabien Poulard * @author Jérôme Rocheteau * * @license Apache 2.0 */ public FSIterator subiterator(JCas theDocument, Annotation theAnnotation,Type theType,boolean isStrict) { // Ajout: déclaration de la variable type Type theAnnotationType = theAnnotation.getType(); // On utilise le constraint factory ConstraintFactory theConstraints = theDocument.getConstraintFactory(); // On définit les contraintes sur le début de l'annotation FSIntConstraint beginConstraint = theConstraints.createIntConstraint(); if (isStrict) { beginConstraint.eq(theAnnotation.getBegin()); } else { beginConstraint.geq(theAnnotation.getBegin()); } Feature beginFeature = theAnnotationType.getFeatureByBaseName("begin"); FeaturePath beginPath = theDocument.createFeaturePath(); beginPath.addFeature(beginFeature); FSMatchConstraint begin = theConstraints.embedConstraint(beginPath,beginConstraint); // ... puis sur la fin de l'annotation FSIntConstraint endConstraint = theConstraints.createIntConstraint(); if (isStrict) { endConstraint.eq(theAnnotation.getEnd()); } else { endConstraint.leq(theAnnotation.getEnd()); } Feature endFeature = theAnnotationType.getFeatureByBaseName("end"); FeaturePath endPath = theDocument.createFeaturePath(); endPath.addFeature(endFeature); FSMatchConstraint end = theConstraints.embedConstraint(endPath, endConstraint); // JR: on définit une contrainte sur le type d'annotation FSTypeConstraint typeConstraint = theConstraints.createTypeConstraint(); typeConstraint.add(theType); // FeaturePath typePath = theDocument.createFeaturePath(); FSMatchConstraint type = theConstraints.embedConstraint(typePath, typeConstraint); // On combine les contraintes FSMatchConstraint beginAndEnd = theConstraints.and(type,theConstraints.and(begin, end)); // On génère un itérateur respectant ces contraintes FSIterator filteredIterator = theDocument.createFilteredIterator(theDocument.getAnnotationIndex().iterator(), beginAndEnd); return filteredIterator; }
Cette méthode prend en paramètre le JCas dans lequel travailler, l'annotation couvrante (l'annotation A3 dans l'exemple précédent), le type d'annotation qui nous intéresse (le type B pour reprendre l'exemple précédent) et un booléen qui permet de préciser si l'on souhaite une correspondance exacte ou approximative des frontières.
aucun commentaire