在不重新加载 ontology 的情况下,无法检索通过 OWL API 添加的命名个人的推论

Cannot retrieve inferences for named individual added via OWL API without reloading ontology

在我的应用程序中,我需要将指定的个人添加到 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);
        }
    }
}

这是我用来测试的简单 ontology:

<?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 仅 returns owl:ThingOpenllet 什么也没有。但是,当我将对 ontology 的更改保存到文件并重新加载它时,我可以找到我使用这些推理器中的任何一个添加的个人的推断类型。

我已经用 OWL API 的 5.1.2 和 4.5.0 版本对此进行了测试。我也尝试过调用 reasoner.precomputeInferences(),尽管文档说明这不是必需的,但没有任何区别。

问题是推理器确实在创建推理器时使用了 ontology。如果您使用 Protege(桌面),我现在不知道,它在后台使用 OWL API。我这样做并且还在 Protege 中使用了推理器,您应该注意到在对 ontology 进行更改后必须刷新推理器。在 Protege 中,这也显示在 window.

底部的状态行中

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

reasoner = reasonerFactory.createReasoner(ontology);

此致

延斯

reasonerFactory.createReasoner(ontology) 创建一个缓冲推理器,即它必须在您更改 ontology.

后手动同步

来自 Javadoc 的更多详细信息:

Ontology Change Management (Buffering and Non-Buffering Modes)

At creation time, an OWLReasoner will load the axioms in the root ontology imports closure. It will attach itself as a listener to the OWLOntologyManager that manages the root ontology. The reasoner will listen to any OWLOntologyChanges and respond appropriately to them before answering any queries. If the BufferingMode of the reasoner (the answer to getBufferingMode() is BufferingMode.NON_BUFFERING) the ontology changes are processed by the reasoner immediately so that any queries asked after the changes are answered with respect to the changed ontologies. If the BufferingMode of the reasoner is BufferingMode.BUFFERING then ontology changes are stored in a buffer and are only taken into consideration when the buffer is flushed with the flush() method. When reasoning, axioms in the root ontology imports closure, minus the axioms returned by the getPendingAxiomAdditions() method, plus the axioms returned by the getPendingAxiomRemovals() are taken into consideration. Note that there is no guarantee that the reasoner implementation will respond to changes in an incremental (and efficient manner) manner.

两个选项:

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