Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imports closure of deep-copied ontology is different from the original one #969

Closed
fanavarro opened this issue Sep 9, 2020 · 4 comments
Closed

Comments

@fanavarro
Copy link
Contributor

Hi everyone. I found an strange behavior when copying ontologies, and I am not very sure if it is a bug or not (maybe related with #480).

My problem is about deep copy of ontologies with imports. I have a main ontology that imports another ones. I created an ontology manager that loads all of them in the correct dependency order. After all ontologies are correctly loaded in the manager, I perform deep copy of the main one, by using another ontology manager, in order to manipulate it without modifying the original one. When I save this ontology into a file, imports are still there and I can browse the imported ontologies after loading the main one into protege. However, if I try to use a reasoner with the copied ontology before saving it into the disk, I see that some axioms are not inferred.

After some research, I've figured out that the method OWLOntology.importsClosure() is not returning the imported ontologies after the deep copy. I think this would cause the strange behavior of reasoners, which work with the axioms stored in the ontologies returned by importsClosure method.

I used the following piece of code, in which I have added some debug messages, for getting a copy of ontologies stored in my ontology manager by their IRIs:

/**
 * Returns a copy of the ontology whose IRI is passed as argument. This copy
 * is managed by another OWLOntologyManager. We do not want to modify the original
 * version of the ontology when adding instances from different data sources.
 */
public OWLOntology getOntologyByIRI(IRI iri) throws OWLOntologyCreationException {
	OWLOntology originalOntology = getOntologyManager().getOntology(iri);
	System.out.println("Imports closure in original ontology:");
	for(OWLOntology importedOnt : originalOntology.importsClosure().collect(Collectors.toList())){
		System.out.println(importedOnt.getOntologyID());
	}
	
	OWLOntology copyOntology = OWLManager.createOWLOntologyManager().copyOntology(originalOntology, OntologyCopy.DEEP);
	
	System.out.println("Imports closure in deep-copied ontology:");
	for(OWLOntology importedOnt : copyOntology.importsClosure().collect(Collectors.toList())){
		System.out.println(importedOnt.getOntologyID());
	}
	
	return copyOntology;
}

The debug messages that this method prints are the following:

Imports closure in original ontology:
OntologyID(OntologyIRI(<http://purl.org/biotop/btl2.owl>) VersionIRI(<null>))
OntologyID(OntologyIRI(<http://snomed.info/sct/HRCMJULY18.owl>) VersionIRI(<null>))
OntologyID(OntologyIRI(<http://snomed.info/sct/SCTJULY20_STROKE.owl>) VersionIRI(<null>))
OntologyID(OntologyIRI(<http://www.semanticweb.org/catimc/ontologies/2018/6/SCT-BTL2>) VersionIRI(<null>))
OntologyID(OntologyIRI(<http://www.semanticweb.org/catimc/ontologies/2018/6/SemanticDataModel>) VersionIRI(<null>))
OntologyID(OntologyIRI(<http://www.semanticweb.org/catimc/ontologies/2018/7/Precise4Q>) VersionIRI(<null>))

Imports closure in deep-copied ontology:
OntologyID(OntologyIRI(<http://www.semanticweb.org/catimc/ontologies/2018/7/Precise4Q>) VersionIRI(<null>))

Therefore, reasoners are not taking into account the axioms included in the imported ontologies when I try to reason over the copied ontology. Could this be a bug? Or maybe I am doing something wrong?

Greetings!

@fanavarro
Copy link
Contributor Author

The reasoning process has the desired behavior when I also copy the imported ontologies into the new created ontology manager as follows:

	public OWLOntology getOntologyByIRI(IRI iri) throws OWLOntologyCreationException {
		OWLOntology originalOntology = getOntologyManager().getOntology(iri);
		OWLOntologyManager newOntologyManager = OWLManager.createOWLOntologyManager();
		OWLOntology copyOntology = newOntologyManager.copyOntology(originalOntology, OntologyCopy.DEEP);
		
		for(OWLOntology importedOnt : originalOntology.imports().collect(Collectors.toList())){
			newOntologyManager.copyOntology(importedOnt, OntologyCopy.DEEP);
		}
		return copyOntology;
	}

Maybe this copy of the imported ontologies into the new ontology manager should be done by the method copyOntology? I am not sure about the implications of this kind of things.

@ignazio1977
Copy link
Contributor

The OntologyCopy options do not include the imports closure of the ontology, they refer to other information that the manager holds, such as document IRI and ontology format.

Imported ontologies are needed, of course, for correct reasoning, but they need to be copied/moved manually. The imported ontologies are loaded automatically only when an ontology is parsed, not when it's manually created or moved - this because (as it was determined by tool developers many years ago) a common use case was to create ontologies that imported a number of large upper ontologies, and contained very few, if any, axioms of their own. Having to load the imported ontologies when imports are declared would make this sort of task very time/memory/network consuming, while leaving the ontology loading as a separate task would allow this to be completed quickly.

Copying and moving ontologies, a more recent feature, was designed to be able to take an ontology out of a manager and into another without the need to parse it again or to make expensive copies.

Moving import closures feels like an obvious next step, but one that's not supported by existing code.
Speaking of desired features, would you expect the imports closure to be duplicated or moved?

@fanavarro
Copy link
Contributor Author

Hi @ignazio1977, thanks for your explanation.

Moving or copying import closures is a very good point to think about. For me, it is difficult to take a decision because, in the end, an import is a reference to other ontology in your OWL file. If you make a deep copy of your ontology, the imported ontologies will point to the same reference than the original one so that changes in the imported ontologies will affect to both the original and the copied ontology. This could be solved by copying the imported ontologies, but this could provoke a bad performance with big imported ontologies. I think the best solution would be let the owlapi user to chose if he or she wants to copy or to move the import closure when copying an ontology. Could this be done by some kind of parameter?

@ignazio1977
Copy link
Contributor

f39f6bb for version 6 introduces more values for OntologyCopy and also turns it into an interface, so you are able to inject behaviour closer to your needs.

For version 5 and older, you can use the same code I've added inside version 6; it takes all ontologies in the imports closure and applies the same copyOntology method to each one:

    // if the imports closure must be treated the same way, do so for all of the ontologies
    // contained - except this one
    if (settings.applyToImportsClosure()) {
        OntologyCopy newSettings = new OntologyCopyWrapper(settings);
        List<OWLOntology> importsToCopy =
            asList(toCopy.importsClosure().filter(x -> !toCopy.equals(x)));
        for (OWLOntology o : importsToCopy) {
            copyOntology(o, newSettings);
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants