Search in sources :

Example 6 with RelationAdapter

use of de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter in project webanno by webanno.

the class AnnotationSchemaServiceImpl method getAttachedRels.

@Override
@Transactional
public List<AttachedAnnotation> getAttachedRels(AnnotationLayer aLayer, AnnotationFS aFs) {
    CAS cas = aFs.getCAS();
    List<AttachedAnnotation> result = new ArrayList<>();
    for (AnnotationLayer relationLayer : listAttachedRelationLayers(aLayer)) {
        RelationAdapter relationAdapter = (RelationAdapter) getAdapter(relationLayer);
        Type relationType = CasUtil.getType(cas, relationLayer.getName());
        Feature sourceFeature = relationType.getFeatureByBaseName(relationAdapter.getSourceFeatureName());
        Feature targetFeature = relationType.getFeatureByBaseName(relationAdapter.getTargetFeatureName());
        // This code is already prepared for the day that relations can go between
        // different layers and may have different attach features for the source and
        // target layers.
        Feature relationSourceAttachFeature = null;
        Feature relationTargetAttachFeature = null;
        if (relationAdapter.getAttachFeatureName() != null) {
            relationSourceAttachFeature = sourceFeature.getRange().getFeatureByBaseName(relationAdapter.getAttachFeatureName());
            relationTargetAttachFeature = targetFeature.getRange().getFeatureByBaseName(relationAdapter.getAttachFeatureName());
        }
        for (AnnotationFS relationFS : CasUtil.select(cas, relationType)) {
            if (!(relationFS instanceof AnnotationFS)) {
                continue;
            }
            // Here we get the annotations that the relation is pointing to in the UI
            AnnotationFS sourceFS;
            if (relationSourceAttachFeature != null) {
                sourceFS = (AnnotationFS) relationFS.getFeatureValue(sourceFeature).getFeatureValue(relationSourceAttachFeature);
            } else {
                sourceFS = (AnnotationFS) relationFS.getFeatureValue(sourceFeature);
            }
            AnnotationFS targetFS;
            if (relationTargetAttachFeature != null) {
                targetFS = (AnnotationFS) relationFS.getFeatureValue(targetFeature).getFeatureValue(relationTargetAttachFeature);
            } else {
                targetFS = (AnnotationFS) relationFS.getFeatureValue(targetFeature);
            }
            if (sourceFS == null || targetFS == null) {
                StringBuilder message = new StringBuilder();
                message.append("Relation [" + relationAdapter.getLayer().getName() + "] with id [" + getAddr(relationFS) + "] has loose ends - cannot identify attached annotations.");
                if (relationAdapter.getAttachFeatureName() != null) {
                    message.append("\nRelation [" + relationAdapter.getLayer().getName() + "] attached to feature [" + relationAdapter.getAttachFeatureName() + "].");
                }
                message.append("\nSource: " + sourceFS);
                message.append("\nTarget: " + targetFS);
                log.warn("{}", message.toString());
                continue;
            }
            boolean isIncoming = isSame(targetFS, aFs);
            boolean isOutgoing = isSame(sourceFS, aFs);
            if (isIncoming && isOutgoing) {
                result.add(new AttachedAnnotation(relationLayer, relationFS, sourceFS, LOOP));
            } else if (isIncoming) {
                result.add(new AttachedAnnotation(relationLayer, relationFS, sourceFS, INCOMING));
            } else if (isOutgoing) {
                result.add(new AttachedAnnotation(relationLayer, relationFS, targetFS, OUTGOING));
            }
        }
    }
    return result;
}
Also used : RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) Type(org.apache.uima.cas.Type) WebAnnoCasUtil.isNativeUimaType(de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.isNativeUimaType) CAS(org.apache.uima.cas.CAS) ArrayList(java.util.ArrayList) AnnotationLayer(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer) Feature(org.apache.uima.cas.Feature) AnnotationFeature(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature) AttachedAnnotation(de.tudarmstadt.ukp.clarin.webanno.api.AttachedAnnotation) Transactional(org.springframework.transaction.annotation.Transactional)

Example 7 with RelationAdapter

use of de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter in project webanno by webanno.

the class RelationRendererTest method thatRelationOverlapBehaviorOnRenderGeneratesErrors.

@Test
public void thatRelationOverlapBehaviorOnRenderGeneratesErrors() throws Exception {
    TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class);
    builder.buildTokens(jcas, "This is a test .\nThis is sentence two .");
    for (Token t : select(jcas, Token.class)) {
        POS pos = new POS(jcas, t.getBegin(), t.getEnd());
        t.setPos(pos);
        pos.addToIndexes();
    }
    RelationAdapter adapter = new RelationAdapter(layerSupportRegistry, featureSupportRegistry, null, depLayer, FEAT_REL_TARGET, FEAT_REL_SOURCE, () -> asList(dependencyLayerGovernor, dependencyLayerDependent), behaviors);
    List<POS> posAnnotations = new ArrayList<>(select(jcas, POS.class));
    POS source = posAnnotations.get(0);
    POS target = posAnnotations.get(1);
    RelationRenderer sut = new RelationRenderer(adapter, layerSupportRegistry, featureSupportRegistry, asList(new RelationOverlapBehavior()));
    // Create two annotations stacked annotations
    depLayer.setOverlapMode(ANY_OVERLAP);
    AnnotationFS dep1 = adapter.add(document, username, source, target, jcas.getCas());
    AnnotationFS dep2 = adapter.add(document, username, source, target, jcas.getCas());
    {
        depLayer.setOverlapMode(ANY_OVERLAP);
        VDocument vdoc = new VDocument();
        sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
        assertThat(vdoc.comments()).filteredOn(c -> !YIELD.equals(c.getCommentType())).isEmpty();
    }
    {
        depLayer.setOverlapMode(STACKING_ONLY);
        VDocument vdoc = new VDocument();
        sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
        assertThat(vdoc.comments()).filteredOn(c -> !YIELD.equals(c.getCommentType())).isEmpty();
    }
    {
        depLayer.setOverlapMode(OVERLAP_ONLY);
        VDocument vdoc = new VDocument();
        sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
        assertThat(vdoc.comments()).filteredOn(c -> !YIELD.equals(c.getCommentType())).usingFieldByFieldElementComparator().contains(new VComment(dep1, ERROR, "Stacking is not permitted."), new VComment(dep2, ERROR, "Stacking is not permitted."));
    }
    {
        depLayer.setOverlapMode(NO_OVERLAP);
        VDocument vdoc = new VDocument();
        sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
        assertThat(vdoc.comments()).filteredOn(c -> !YIELD.equals(c.getCommentType())).usingFieldByFieldElementComparator().contains(new VComment(dep1, ERROR, "Stacking is not permitted."), new VComment(dep2, ERROR, "Stacking is not permitted."));
    }
    // Remove the stacked annotation and introduce one that is purely overlapping
    adapter.delete(document, username, jcas.getCas(), new VID(dep2));
    depLayer.setOverlapMode(ANY_OVERLAP);
    AnnotationFS dep3 = adapter.add(document, username, source, posAnnotations.get(2), jcas.getCas());
    {
        depLayer.setOverlapMode(NO_OVERLAP);
        VDocument vdoc = new VDocument();
        sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
        assertThat(vdoc.comments()).filteredOn(c -> !YIELD.equals(c.getCommentType())).usingFieldByFieldElementComparator().contains(new VComment(dep1, ERROR, "Overlap is not permitted."), new VComment(dep3, ERROR, "Overlap is not permitted."));
    }
}
Also used : AnnotationFS(org.apache.uima.cas.text.AnnotationFS) FEAT_REL_SOURCE(de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst.FEAT_REL_SOURCE) FEAT_REL_TARGET(de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst.FEAT_REL_TARGET) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) RelationLayerBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationLayerBehavior) Sentence(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence) PROJECT_TYPE_ANNOTATION(de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst.PROJECT_TYPE_ANNOTATION) TokenBuilder(org.apache.uima.fit.testing.factory.TokenBuilder) OVERLAP_ONLY(de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.OVERLAP_ONLY) RelationOverlapBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationOverlapBehavior) ArrayList(java.util.ArrayList) Token(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token) Dependency(de.tudarmstadt.ukp.dkpro.core.api.syntax.type.dependency.Dependency) Arrays.asList(java.util.Arrays.asList) LayerSupportRegistryImpl(de.tudarmstadt.ukp.clarin.webanno.api.annotation.layer.LayerSupportRegistryImpl) JCasFactory(org.apache.uima.fit.factory.JCasFactory) Project(de.tudarmstadt.ukp.clarin.webanno.model.Project) LayerSupportRegistry(de.tudarmstadt.ukp.clarin.webanno.api.annotation.layer.LayerSupportRegistry) SINGLE_TOKEN(de.tudarmstadt.ukp.clarin.webanno.model.AnchoringMode.SINGLE_TOKEN) ANY_OVERLAP(de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.ANY_OVERLAP) Before(org.junit.Before) JCas(org.apache.uima.jcas.JCas) RelationCrossSentenceBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationCrossSentenceBehavior) POS(de.tudarmstadt.ukp.dkpro.core.api.lexmorph.type.pos.POS) NO_OVERLAP(de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.NO_OVERLAP) RelationAttachmentBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAttachmentBehavior) VComment(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VComment) ERROR(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VCommentType.ERROR) YIELD(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VCommentType.YIELD) Test(org.junit.Test) RELATION_TYPE(de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst.RELATION_TYPE) SPAN_TYPE(de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst.SPAN_TYPE) RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) STACKING_ONLY(de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.STACKING_ONLY) List(java.util.List) AnnotationFeature(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature) JCasUtil.select(org.apache.uima.fit.util.JCasUtil.select) AnnotationLayer(de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer) SourceDocument(de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument) VID(de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.VID) FeatureSupportRegistryImpl(de.tudarmstadt.ukp.clarin.webanno.api.annotation.feature.FeatureSupportRegistryImpl) VDocument(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VDocument) FeatureSupportRegistry(de.tudarmstadt.ukp.clarin.webanno.api.annotation.feature.FeatureSupportRegistry) TokenBuilder(org.apache.uima.fit.testing.factory.TokenBuilder) RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) VDocument(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VDocument) ArrayList(java.util.ArrayList) Token(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token) VComment(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VComment) VID(de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.VID) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) POS(de.tudarmstadt.ukp.dkpro.core.api.lexmorph.type.pos.POS) RelationOverlapBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationOverlapBehavior) Sentence(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence) Test(org.junit.Test)

Example 8 with RelationAdapter

use of de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter in project webanno by webanno.

the class RelationRendererTest method thatRelationCrossSentenceBehaviorOnRenderGeneratesErrors.

@Test
public void thatRelationCrossSentenceBehaviorOnRenderGeneratesErrors() throws Exception {
    TokenBuilder<Token, Sentence> builder = new TokenBuilder<>(Token.class, Sentence.class);
    builder.buildTokens(jcas, "This is a test .\nThis is sentence two .");
    for (Token t : select(jcas, Token.class)) {
        POS pos = new POS(jcas, t.getBegin(), t.getEnd());
        t.setPos(pos);
        pos.addToIndexes();
    }
    RelationAdapter adapter = new RelationAdapter(layerSupportRegistry, featureSupportRegistry, null, depLayer, FEAT_REL_TARGET, FEAT_REL_SOURCE, () -> asList(dependencyLayerGovernor, dependencyLayerDependent), behaviors);
    List<POS> posAnnotations = new ArrayList<>(select(jcas, POS.class));
    POS source = posAnnotations.get(0);
    POS target = posAnnotations.get(posAnnotations.size() - 1);
    depLayer.setCrossSentence(true);
    AnnotationFS dep = adapter.add(document, username, source, target, jcas.getCas());
    depLayer.setCrossSentence(false);
    RelationRenderer sut = new RelationRenderer(adapter, layerSupportRegistry, featureSupportRegistry, asList(new RelationCrossSentenceBehavior()));
    VDocument vdoc = new VDocument();
    sut.render(jcas.getCas(), asList(), vdoc, 0, jcas.getDocumentText().length());
    assertThat(vdoc.comments()).usingFieldByFieldElementComparator().contains(new VComment(dep, ERROR, "Crossing sentence boundaries is not permitted."));
}
Also used : TokenBuilder(org.apache.uima.fit.testing.factory.TokenBuilder) RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) RelationCrossSentenceBehavior(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationCrossSentenceBehavior) VDocument(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VDocument) ArrayList(java.util.ArrayList) Token(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token) VComment(de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VComment) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) POS(de.tudarmstadt.ukp.dkpro.core.api.lexmorph.type.pos.POS) Sentence(de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence) Test(org.junit.Test)

Example 9 with RelationAdapter

use of de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter in project webanno by webanno.

the class RelationRenderer method getRelationLinks.

/**
 * Get relation links to display in relation yield
 */
private Map<Integer, Set<Integer>> getRelationLinks(CAS aCas, int aWindowBegin, int aWindowEnd, Type type, Feature dependentFeature, Feature governorFeature, Feature arcSpanFeature) {
    RelationAdapter typeAdapter = getTypeAdapter();
    FeatureStructure dependentFs;
    FeatureStructure governorFs;
    Map<Integer, Set<Integer>> relations = new ConcurrentHashMap<>();
    for (AnnotationFS fs : selectCovered(aCas, type, aWindowBegin, aWindowEnd)) {
        if (typeAdapter.getAttachFeatureName() != null) {
            dependentFs = fs.getFeatureValue(dependentFeature).getFeatureValue(arcSpanFeature);
            governorFs = fs.getFeatureValue(governorFeature).getFeatureValue(arcSpanFeature);
        } else {
            dependentFs = fs.getFeatureValue(dependentFeature);
            governorFs = fs.getFeatureValue(governorFeature);
        }
        if (dependentFs == null || governorFs == null) {
            log.warn("Relation [" + typeAdapter.getLayer().getName() + "] with id [" + getAddr(fs) + "] has loose ends - cannot render.");
            continue;
        }
        Set<Integer> links = relations.get(getAddr(governorFs));
        if (links == null) {
            links = new ConcurrentSkipListSet<>();
        }
        links.add(getAddr(dependentFs));
        relations.put(getAddr(governorFs), links);
    }
    // Update other subsequent links
    for (int i = 0; i < relations.keySet().size(); i++) {
        for (Integer fs : relations.keySet()) {
            updateLinks(relations, fs);
        }
    }
    // to start displaying the text from the governor, include it
    for (Integer fs : relations.keySet()) {
        relations.get(fs).add(fs);
    }
    return relations;
}
Also used : FeatureStructure(org.apache.uima.cas.FeatureStructure) RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) Set(java.util.Set) ConcurrentSkipListSet(java.util.concurrent.ConcurrentSkipListSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 10 with RelationAdapter

use of de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter in project webanno by webanno.

the class RemoveDanglingRelationsRepair method repair.

@Override
public void repair(Project aProject, CAS aCas, List<LogMessage> aMessages) {
    Set<FeatureStructure> nonIndexed = getNonIndexedFSes(aCas);
    Set<FeatureStructure> toDelete = new LinkedHashSet<>();
    for (AnnotationFS fs : aCas.getAnnotationIndex()) {
        Type t = fs.getType();
        Feature sourceFeat = t.getFeatureByBaseName(FEAT_REL_SOURCE);
        Feature targetFeat = t.getFeatureByBaseName(FEAT_REL_TARGET);
        // Is this a relation?
        if (!(sourceFeat != null && targetFeat != null)) {
            continue;
        }
        FeatureStructure source = fs.getFeatureValue(sourceFeat);
        FeatureStructure target = fs.getFeatureValue(targetFeat);
        // Are there null end-points or does it point to deleted spans?
        if (source == null || target == null || nonIndexed.contains(source) || nonIndexed.contains(target)) {
            toDelete.add(fs);
            continue;
        }
        RelationAdapter relationAdapter = (RelationAdapter) annotationService.findAdapter(aProject, fs);
        Feature relationSourceAttachFeature = null;
        Feature relationTargetAttachFeature = null;
        if (relationAdapter.getAttachFeatureName() != null) {
            relationSourceAttachFeature = sourceFeat.getRange().getFeatureByBaseName(relationAdapter.getAttachFeatureName());
            relationTargetAttachFeature = targetFeat.getRange().getFeatureByBaseName(relationAdapter.getAttachFeatureName());
        }
        // Here we get the annotations that the relation is pointing to in the UI
        if (relationSourceAttachFeature != null) {
            source = (AnnotationFS) source.getFeatureValue(relationSourceAttachFeature);
        }
        if (relationTargetAttachFeature != null) {
            target = (AnnotationFS) target.getFeatureValue(relationTargetAttachFeature);
        }
        // annotations linked to in the UI?
        if (source == null || target == null || nonIndexed.contains(source) || nonIndexed.contains(target)) {
            toDelete.add(fs);
            continue;
        }
    }
    // Delete those relations that pointed to deleted spans
    if (!toDelete.isEmpty()) {
        toDelete.forEach(aCas::removeFsFromIndexes);
        aMessages.add(new LogMessage(this, INFO, "Removed [%d] dangling relations.", toDelete.size()));
    }
}
Also used : FeatureStructure(org.apache.uima.cas.FeatureStructure) LinkedHashSet(java.util.LinkedHashSet) AnnotationFS(org.apache.uima.cas.text.AnnotationFS) RelationAdapter(de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter) Type(org.apache.uima.cas.Type) LogMessage(de.tudarmstadt.ukp.clarin.webanno.support.logging.LogMessage) Feature(org.apache.uima.cas.Feature)

Aggregations

RelationAdapter (de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationAdapter)14 AnnotationFS (org.apache.uima.cas.text.AnnotationFS)11 AnnotationFeature (de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature)7 Type (org.apache.uima.cas.Type)7 ArrayList (java.util.ArrayList)6 Feature (org.apache.uima.cas.Feature)6 CAS (org.apache.uima.cas.CAS)5 FeatureStructure (org.apache.uima.cas.FeatureStructure)5 VID (de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.VID)4 SpanAdapter (de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.SpanAdapter)3 VComment (de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VComment)3 VDocument (de.tudarmstadt.ukp.clarin.webanno.api.annotation.rendering.model.VDocument)3 AnnotationLayer (de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer)3 SourceDocument (de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument)3 Set (java.util.Set)3 CasUtil.getType (org.apache.uima.fit.util.CasUtil.getType)3 AttachedAnnotation (de.tudarmstadt.ukp.clarin.webanno.api.AttachedAnnotation)2 RelationCrossSentenceBehavior (de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationCrossSentenceBehavior)2 RelationLayerBehavior (de.tudarmstadt.ukp.clarin.webanno.api.annotation.adapter.RelationLayerBehavior)2 FeatureSupportRegistry (de.tudarmstadt.ukp.clarin.webanno.api.annotation.feature.FeatureSupportRegistry)2