Hi Roberto,
here's an alternative to your solution. It's a bit
shorter, and I find it easier to understand ;-)
It's untested, but you get the idea.
--Thilo
/**
* Find a covering parent annotation of a certain type, e.g., the sentence
containing a given
* annotation.
*
* @param cas
* The CAS.
* @param childAnnotation
* The annotation that we want to find a parent for (e.g., a token).
* @param parentType
* The type of covering annotation we're looking for.
* @return A parent annotation, if it exists; <code>null</code> else.
*/
public static FeatureStructure findParentAnnotation(CAS cas, AnnotationFS
childAnnotation,
Type parentType) {
final int start = childAnnotation.getBegin();
final int end = childAnnotation.getEnd();
// Find a parent FS by searching in the annotation index. Start by creating
a temp parent FS
// which is only used to position an iterator. If this is done many times,
the search FS should
// be cached and only the start/end position modified as necessary
(creating a FS allocates
// space in the CAS that is not garbage collected).
FeatureStructure searchFS = cas.createAnnotation(parentType, start, end);
FSIterator parentIterator = cas.getAnnotationIndex(parentType).iterator();
// Position the iterator.
parentIterator.moveTo(searchFS);
// Return parent at position if it is indeed a covering annotation.
if (parentIterator.isValid()) {
AnnotationFS candidateParent = (AnnotationFS) parentIterator.get();
if ((candidateParent.getBegin() <= start) && (candidateParent.getEnd() >=
end)) {
return candidateParent;
}
}
// If no parent annotation could be found.
return null;
}
Roberto Franchini wrote:
On Wed, Jan 7, 2009 at 11:55 AM, Roberto Franchini
<[email protected]> wrote:
Hi,
I need to get a parent annotation of a given one.
Example: given a Token annotation, I want to know the parent Sentence.
I need to extract it from a cas. Maybe filters or constraint?
I mean a sort of "parentIterator", as the subiterator, but "reversed" :)
Regards,
Roberto
Here's the answer with filtered iterator:
public static FSIterator getAnnotationParent(JCas jcas, Annotation
son, Type parent) {
ConstraintFactory cf = jcas.getConstraintFactory();
FSIntConstraint beginCons = cf.createIntConstraint();
beginCons.leq(son.getBegin());
FSIntConstraint endCons = cf.createIntConstraint();
endCons.geq(son.getEnd());
FSTypeConstraint typeCons = cf.createTypeConstraint();
Type type = jcas.getTypeSystem().getType(parent.getName());
typeCons.add(type);
Feature beginFeature = type.getFeatureByBaseName("begin");
FeaturePath beginPath = jcas.createFeaturePath();
beginPath.addFeature(beginFeature);
Feature endFeature = type.getFeatureByBaseName("end");
FeaturePath endPath = jcas.createFeaturePath();
endPath.addFeature(endFeature);
FSMatchConstraint begin = cf.embedConstraint(beginPath,
beginCons);
FSMatchConstraint end = cf.embedConstraint(endPath, endCons);
FSMatchConstraint beginAndEnd = cf.and(begin, end);
FSMatchConstraint beginAndEndAndType = cf.and(beginAndEnd,
typeCons);
FSIterator filteredIterator =
jcas.createFilteredIterator(jcas.getAnnotationIndex(parent).iterator(),
beginAndEndAndType);
return filteredIterator;
}
Here's a test (junit).
@Test
public void getParent() throws Exception {
AnalysisEngine tokenizer = AnnotatorFactory.createTokenizer();
//this is my own factory for tests!!!
JCas jcas = tokenizer.newJCas();
jcas.setDocumentText("My name is .");
Sentence sentence = new Sentence(jcas, 0,
jcas.getDocumentText().length());
sentence.addToIndexes();
tokenizer.process(jcas);
FSIterator iterator =
jcas.getAnnotationIndex(Token.type).iterator();
iterator.moveToNext();
Token token = (Token) iterator.get();
FSIterator parentIt = CasUtil.getAnnotationParent(jcas, token,
sentence.getType());
assertNotNull(parentIt);
parentIt.moveToFirst();
Sentence sentence2 = (Sentence) parentIt.get();
assertNotNull(sentence2);
assertEquals(sentence.getCoveredText(),
sentence2.getCoveredText());
}
It works :)
Roberto