无法在不重新加载本体的情况下检索通过OWL API添加的命名个体的推断

时间:2017-10-26 09:37:10

标签: api owl ontology

在我的应用程序中,我需要将命名个体添加到本体。稍后我需要能够检索这些命名的个体并确定它们的推断类型,但由于某种原因,我无法检索它们的类型。根据我使用的OWL推理器,我得到异常或空集。

以下是一个说明问题的自包含示例:

package owl.api.test.StandaloneOWLNamedIndividualRetrievalv5;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.stream.Collectors;

import org.semanticweb.HermiT.ReasonerFactory;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.model.PrefixManager;
import org.semanticweb.owlapi.model.parameters.ChangeApplied;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.search.EntitySearcher;
import org.semanticweb.owlapi.util.DefaultPrefixManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import openllet.owlapi.OpenlletReasonerFactory;
import uk.ac.manchester.cs.jfact.JFactFactory;

public class App {
    private static Logger logger = LoggerFactory
        .getLogger(owl.api.test.StandaloneOWLNamedIndividualRetrievalv5.App.class);
    // Why This Failure marker
    private static final Marker WTF_MARKER = MarkerFactory.getMarker("WTF");

    public static void main(String[] args) {
        try {
            // Setup physical IRI for storing ontology
            Path path = Paths.get(".").toAbsolutePath().normalize();
            IRI loadDocumentIRI = IRI.create("file:" + path.toFile().getAbsolutePath() + "/SimpleOntology.owl");
            logger.trace("documentIRI=" + loadDocumentIRI);
            IRI saveDocumentIRI = IRI.create("file:" + path.toFile().getAbsolutePath() + "/SimpleOntologyUpdated.owl");
            logger.trace("documentIRI=" + saveDocumentIRI);

            // Initialize
            OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
            OWLDataFactory dataFactory = manager.getOWLDataFactory();
            OWLOntology ontology = manager.loadOntologyFromOntologyDocument(loadDocumentIRI);
            // OWLReasonerFactory reasonerFactory = new JFactFactory();
            OWLReasonerFactory reasonerFactory = new ReasonerFactory();
//          OWLReasonerFactory reasonerFactory = OpenlletReasonerFactory.getInstance();
            OWLReasoner reasoner = reasonerFactory.createReasoner(ontology);
            PrefixManager pm = new DefaultPrefixManager(ontology.getOntologyID().getOntologyIRI().get().getIRIString());

            // Get references to a new named individual and an existing class
            OWLIndividual individual = dataFactory.getOWLNamedIndividual("#ind1", pm);
            OWLClass owlClass = dataFactory.getOWLClass("#ClassB", pm);

            // Create class assertion axiom
            OWLClassAssertionAxiom classAssertionAxiom = dataFactory.getOWLClassAssertionAxiom(owlClass, individual);

            // Add class assertion axiom to ontology
            ChangeApplied changeApplied = manager.addAxiom(ontology, classAssertionAxiom);
            logger.trace("ChangeApplied = " + changeApplied);
            if (changeApplied.equals(ChangeApplied.SUCCESSFULLY)) {
                try {
                    manager.saveOntology(ontology, saveDocumentIRI);
                } catch (OWLOntologyStorageException e) {
                    logger.error(e.getMessage());
                }
            }

           // Now try to retrieve the individual
           logger.trace(
                "Trying to retrieve individual = " + classAssertionAxiom.getIndividual().asOWLNamedIndividual());
           Set<Object> classExpressionTypes = EntitySearcher.getTypes(classAssertionAxiom.getIndividual(), ontology)
                .collect(Collectors.toSet());
           logger.trace("Individual = " + classAssertionAxiom.getIndividual() + " has types based on EntitySearcher "
                + classExpressionTypes);
           NodeSet<OWLClass> types = reasoner.getTypes(classAssertionAxiom.getIndividual().asOWLNamedIndividual(),
                false);
           logger.trace("Individual = " + classAssertionAxiom.getIndividual()
                + " has types based on reasoner.getTypes " + types);
        } catch (Throwable t) {
           logger.error(WTF_MARKER, t.getMessage(), t);
        }
    }
}

这是我用来测试的简单本体:

<?xml version="1.0"?>
<rdf:RDF xmlns="http://www.semanticweb.org/2017/simple#"
 xml:base="http://www.semanticweb.org/2017/simple"
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:owl="http://www.w3.org/2002/07/owl#"
 xmlns:xml="http://www.w3.org/XML/1998/namespace"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
 xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<owl:Ontology rdf:about="http://www.semanticweb.org/2017/simple"/>

<owl:Class rdf:about="http://www.semanticweb.org/2017/simple#ClassA"/>
<owl:Class rdf:about="http://www.semanticweb.org/2017/simple#ClassB">
    <rdfs:subClassOf rdf:resource="http://www.semanticweb.org/2017/simple#ClassA"/>
</owl:Class>
</rdf:RDF>

运行此代码后,我希望它会确定单个ind1的类型为ThingClassAClassB

认为此问题可能与特定的OWL推理器有关,我尝试使用JFactHermiTOpenlletJFact引发NullPointerExceptionHermiT仅返回owl:ThingOpenllet。但是,当我将对本体的更改保存到文件并重新加载时,我可以找到使用任何这些reasoners添加的个体的推断类型。

我已经使用OWL API的5.1.2和4.5.0版进行了测试。我也试过调用reasoner.precomputeInferences(),即使文档声明这不是必要的,但它没有任何区别。

2 个答案:

答案 0 :(得分:2)

reasonerFactory.createReasoner(ontology)创建一个缓冲推理器,即在更改本体后必须手动同步。

来自Javadoc的更多细节:

  

本体变更管理(缓冲和非缓冲模式)

     

在创建时,OWLReasoner将在根中加载公理   本体进口关闭。它将自己作为一个倾听者   管理根本体的OWLOntologyManager。推理者会   听取任何OWLOntologyChanges并对他们做出适当的回应   在回答任何疑问之前。如果是推理者的BufferingMode   (getBufferingMode()的答案是BufferingMode.NON_BUFFERING)   本体更改由推理器立即处理,以便任何   在对更改进行回答后询问   改变了本体论。如果推理器的BufferingMode是   BufferingMode.BUFFERING然后将本体更改存储在缓冲区中   并且仅在使用冲洗缓冲区时将其考虑在内   flush()方法。在推理时,根本体中的公理   进口封闭,减去由此返回的公理   getPendingAxiomAdditions()方法,加上由公式返回的公理   getPendingAxiomRemovals()被考虑在内。注意   无法保证推理器的实施会响应   以增量(和有效方式)方式改变。

两个选项:

  1. 在您向推理人询问推理之前,请致电reasoner.flush()
  2. 创建非缓冲推理器,即使用reasonerFactory.createNonBufferingReasoner(ontology)

答案 1 :(得分:0)

问题在于推理者确实使用了本体论是在创建推理器的时候。我现在不使用Protege(桌面),它使用底层的OWL API。我这样做并且在Protege中使用推理器你应该注意到在更改本体之后你必须刷新推理器。在Protege中,这也在窗口底部的状态行中指示。

每次更改本体时都必须重新创建推理器。解决您的示例中的问题在检索个体的块之前添加以下行:

reasoner = reasonerFactory.createReasoner(ontology);

祝你好运