Difference between revisions of "BeanShell"

From Protege Wiki
Jump to: navigation, search
(Duplicated Axioms)
(Duplicated Axioms)
Line 347: Line 347:
 
};
 
};
 
</pre>
 
</pre>
 +
 +
== Missing Annotation Properties ==

Revision as of 11:52, June 15, 2011

The BeanShell

As a Protege developer, I have a unique ability to answer complex questions about large ontologies. All I have to do is to start Protege inside eclipse, open the ontology and set a breakpoint and I will have access to a full array of powerful Java tools for analyzing the ontology. These tools range from the full set of OWL API features, direct access to reasoners and the ability to make a complex script out of simple primitives. I have often thought that this power would be much more useful in the hands of the end user but it has been unclear how to get there. What is really needed is a very powerful scripting language.

The beanshell (a CO-ODE plugin developed at the University of Manchester) can fill some of these needs. The primary disadvantage of the bean shell is that it requires some experience with Java and knowledge of the OWL API. This will severely limit the audience but I thought it would still be useful to include some pages on how to use the beanshell. The beanshell also requires some understanding of the Protege API but to start with all that is really needed is to know one call:

      ontology = mngr.getActiveOntology();

Here the mgnr is the Protege Model Manager which keeps track of such things as which ontologies are displayed, how enties in the ontology should be display and the active OWL reasoner.

Some documentation for the beanshell can be found here. My idea in writing this page was to supplement that page with some examples of queries that I have used in my work.

Property Puns

I am just starting this page so I will start with a query that is so simple that it could have been done even in a simple language like SPARQL. I will look at properties that are punned with each other. Any such problem represents a problem in the ontology. To make this interesting I will show what happens when I run this script on the foaf ontology which is known to have some problems as an OWL 2 file. The script is as follows:

OWLOntology ontology = mngr.getActiveOntology();
print("\nActive Ontology = " + ontology);

for (OWLAnnotationProperty ap : ontology.getAnnotationPropertiesInSignature()) {
    if (ontology.containsDataPropertyInSignature(ap.getIRI())) {
       print("The annotation property " + ap.toString()
                                 + " is also a data property");
    }
}

for (OWLAnnotationProperty ap : ontology.getAnnotationPropertiesInSignature()) {
    if (ontology.containsObjectPropertyInSignature(ap.getIRI())) {
       print("The Annotation Property " + ap.toString() 
                                + " is also an object property");
    }
}

for (OWLDataProperty dp : ontology.getDataPropertiesInSignature()) {
    if (ontology.containsObjectPropertyInSignature(dp.getIRI())) {
       print("The data property " + dp.toString() 
                      + " is also an object property");
    }
}

This script can either be run interactively:

bsh % ontology = mngr.getActiveOntology();
bsh % print(ontology);
Ontology(<http://xmlns.com/foaf/0.1/> [Axioms: 550] [Logical axioms: 157])
bsh % 

or by being copied into a file and then run with the Run script command. The output looks like this:

Active Ontology = Ontology(<http://xmlns.com/foaf/0.1/> [Axioms: 550] [Logical axioms: 157])
The annotation property <http://xmlns.com/foaf/0.1/name> is also a data property
The data property <http://xmlns.com/foaf/0.1/yahooChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/mbox_sha1sum> is also an object property
The data property <http://xmlns.com/foaf/0.1/jabberID> is also an object property
The data property <http://xmlns.com/foaf/0.1/icqChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/msnChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/aimChatID> is also an object property

This is useful information to know about this ontology because each of these puns represents a potential problem for ontologies that import the foaf ontology and are saved in the popular RDF/XML format. Just to give some notion of the interactive nature of the development of this script, here is a run with some errors that I corrected:

bsh % for (OWLDatatypeProperty dp : ontology.getAnnotationPropertiesInSignature()) {
    if (ontology.containsObjectPropertyInSignature(dp.getIRI())) {
       print("The data property " + dp.toString() 
                      + " is also an object property");
    }
}
// Error: EvalError: Class: OWLDatatypeProperty not found in namespace : at Line: 1 : in file: <unknown file> : OWLDatatypeProperty 

bsh % for (OWLDataProperty dp : ontology.getAnnotationPropertiesInSignature()) {
    if (ontology.containsObjectPropertyInSignature(dp.getIRI())) {
       print("The data property " + dp.toString() 
                      + " is also an object property");
    }
}
// Error: // Uncaught Exception: for loop iterator variable:dp: null : at Line: 1 : in file: <unknown file> : for ( OWLDataProperty dp : ontology .getAnnotationPropertiesInSignature ( ) ) { 

Target exception: java.lang.ClassCastException: Cannot cast uk.ac.manchester.cs.owl.owlapi.OWLAnnotationPropertyImpl to org.semanticweb.owlapi.model.OWLDataProperty

bsh % for (OWLDataProperty dp : ontology.getDataPropertiesInSignature()) {
    if (ontology.containsObjectPropertyInSignature(dp.getIRI())) {
       print("The data property " + dp.toString() 
                      + " is also an object property");
    }
}
The data property <http://xmlns.com/foaf/0.1/yahooChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/mbox_sha1sum> is also an object property
The data property <http://xmlns.com/foaf/0.1/jabberID> is also an object property
The data property <http://xmlns.com/foaf/0.1/icqChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/msnChatID> is also an object property
The data property <http://xmlns.com/foaf/0.1/aimChatID> is also an object property
bsh % 

It would be better if the bean shell offered some command completion like eclipse and I will see what can be done about this (it might be tricky?).

Counting With a Reasoner

This is a problem that came off the list and it is a bit complicated for the bean shell. But it is a good illustration because it uses several things that might be useful. The user wanted to count the individuals in two classes, calculate the percentage of them that are in the second class and then attach the result to a data property assertion. I am not positive exactly what the data property assertion was supposed to look like but I made an example here. The ontology is as follows:

Prefix(owl:=<http://www.w3.org/2002/07/owl#>)
Prefix(:=<http://www.semanticweb.org/ontologies/2011/5/furniture#>)
Prefix(Marouns_problem:=<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#>)

Ontology(<http://www.semanticweb.org/ontologies/2011/5/furniture>

EquivalentClasses(Marouns_problem:having_final_value_0 ObjectComplementOf(Marouns_problem:having_final_value_1))
EquivalentClasses(Marouns_problem:having_final_value_1 
                  ObjectUnionOf(
                     ObjectSomeValuesFrom(Marouns_problem:has_mechanism owl:Thing) 
                     ObjectSomeValuesFrom(Marouns_problem:has_protocol owl:Thing)
                     ObjectSomeValuesFrom(Marouns_problem:has_service owl:Thing)))

ObjectPropertyRange(Marouns_problem:has_mechanism Marouns_problem:mechanism)
ObjectPropertyRange(Marouns_problem:has_protocol Marouns_problem:protocol)
ObjectPropertyRange(Marouns_problem:has_service Marouns_problem:service)

ClassAssertion(Marouns_problem:moderate Marouns_problem:a)
ClassAssertion(ObjectExactCardinality(1 Marouns_problem:has_mechanism Marouns_problem:mechanism) Marouns_problem:a)
ClassAssertion(ObjectExactCardinality(1 Marouns_problem:has_protocol Marouns_problem:protocol) Marouns_problem:a)
ClassAssertion(ObjectExactCardinality(1 Marouns_problem:has_service Marouns_problem:service) Marouns_problem:a)

ClassAssertion(Marouns_problem:moderate :b)
ClassAssertion(ObjectExactCardinality(1 Marouns_problem:has_mechanism Marouns_problem:mechanism) :b)
ClassAssertion(ObjectExactCardinality(1 Marouns_problem:has_protocol Marouns_problem:protocol) :b)

ClassAssertion(Marouns_problem:moderate :c)

ClassAssertion(Marouns_problem:moderate :d)
ClassAssertion(ObjectExactCardinality(0 Marouns_problem:has_mechanism) :d)
ClassAssertion(ObjectExactCardinality(0 Marouns_problem:has_protocol) :d)
ClassAssertion(ObjectExactCardinality(0 Marouns_problem:has_service) :d)
)

The user wanted to count the number of the individuals that can be inferred to be in either having_final_value_1 or having_final_value_0 and calculate the percentage of those individuals in having_final_value_1. The user then wanted to put the result in some data property assertions (not sure which ones but I implemented something).

I did this with the following bean shell code:

import java.util.List;

import org.protege.editor.owl.model.inference.ReasonerStatus;
import org.protege.editor.owl.model.inference.ReasonerUtilities;

import org.semanticweb.owlapi.reasoner.OWLReasoner;


ReasonerUtilities.warnUserIfReasonerIsNotConfigured(eKit.getOWLWorkspace(), mngr.getOWLReasonerManager());
if (mngr.getOWLReasonerManager().getReasonerStatus() == ReasonerStatus.INITIALIZED) {
    print("Starting run");
    /*
     * Getting the standard variables (e.g. the ontology, reasoner, ontology manager,...
     */
    OWLOntology ontology = mngr.getActiveOntology();
    OWLReasoner reasoner = mngr.getReasoner();
    String NS = "http://www.semanticweb.org/ontologies/2011/5/Marouns_problem";
    OWLOntologyManager manager = mngr.getOWLOntologyManager();
    OWLDataFactory factory = manager.getOWLDataFactory();

    /*
     * Getting entities specific to the particular ontology.
     * They can be tested with print statements (e.g. print(ontology.containsEntityInSignature(value0));)
     */
    OWLClass value0 = factory.getOWLClass(IRI.create(NS + "#having_final_value_0"));
    OWLClass value1 = factory.getOWLClass(IRI.create(NS + "#having_final_value_1"));
    OWLDataProperty percentageProperty = factory.getOWLDataProperty(IRI.create(NS + "#percentage_having_final_value_1"));

    /*
     * Core logic
     */
    Set value0Individuals = reasoner.getInstances(value0, false).getFlattened();
    Set value1Individuals = reasoner.getInstances(value1, false).getFlattened();
    int count0 = value0Individuals.size();
    int count1 = value1Individuals.size();
    float percentage = 100.0f * ((float) count1) / ((float) (count0 + count1));

    List changes = new ArrayList();
    /*
     * Remove existing percentage data property assertions
     */
    for (OWLAxiom axiom : ontology.getReferencingAxioms(percentageProperty)) {
        if (axiom instanceof OWLDataPropertyAssertionAxiom && 
                ((OWLDataPropertyAssertionAxiom) axiom).getProperty().equals(percentageProperty)) {
            changes.add(new RemoveAxiom(ontology, axiom));
        }
    }
    Set individuals = new HashSet();
    individuals.addAll(value0Individuals);
    individuals.addAll(value1Individuals);
    /*
     * Add new percentage data property assertions
     */
    for (OWLNamedIndividual i : individuals) {
        changes.add(new AddAxiom(ontology, factory.getOWLDataPropertyAssertionAxiom(percentageProperty, i, percentage)));
    }
    /*
     * Apply the changes in a single transaction
     */
    manager.applyChanges(changes);
    print("Added percentage data property assertions");
}

It would actually have been much easier for me if I wrote this code in eclipse and then transferred the code to the bean shell. There may be use cases where this is actually exactly the right thing to do. But I wanted to demonstrate the bean shell so I did the exercise in the bean shell. The example above has been polished somewhat so I think it is useful to show the original session and show what hunting and pecking was necessary to make it work. This also shows the advantages of developing through scripting. You can see the results of your work as you go.

2.0b4 - by Pat Niemeyer (pat@pat.net)
bsh % import java.util.List;
bsh % mngr.getReasoner();
bsh % print(mngr.getReasoner());
org.protege.editor.owl.model.inference.NoOpReasoner@34f07ec4
bsh % import org.semanticweb.owlapi.reasoner.OWLReasoner;
bsh % OWLOntology ontology = mngr.getActiveOntology();
bsh % print(ontology);
Ontology(<http://www.semanticweb.org/ontologies/2011/5/furniture> [Axioms: 34] [Logical axioms: 18])
bsh % OWLReasoner reasoner = mngr.getReasoner();
bsh % String NS = "http://www.semanticweb.org/ontologies/2011/5/furniture";
bsh % OWLOntologyManager manager = mngr.getOWLOntologyManager();
bsh % OWLDataFactory factory = manager.getOWLDataFactory();
bsh % print(factory);
org.protege.owlapi.concurrent.SynchronizedOWLDataFactoryImpl@3efd2905
bsh % OWLClass value1 = factory.getOWLClass(IRI.create(NS + "#having_final_value_1");
// Error: Parser Error: Parse error at line 1, column 2803.  Encountered: (
bsh % OWLClass value1 = factory.getOWLClass(IRI.create(NS + "#having_final_value_1"));
bsh % String NS = "http://www.semanticweb.org/ontologies/2011/5/Marouns_Problem";
bsh %  OWLClass value1 = factory.getOWLClass(IRI.create(NS + "#having_final_value_1"));
bsh % print(ontology.containsEntityInSignature(value1));
false
bsh % print(value1)
;
<http://www.semanticweb.org/ontologies/2011/5/Marouns_Problem#having_final_value_1>
bsh % String NS = "http://www.semanticweb.org/ontologies/2011/5/Marouns_problem";
bsh % OWLClass value1 = factory.getOWLClass(IRI.create(NS + "#having_final_value_1"));
bsh % print(ontology.containsEntityInSignature(value1));
true
bsh % OWLClass value0 = factory.getOWLClass(IRI.create(NS + "#having_final_value_0"));
bsh % print(ontology.containsEntityInSignature(value0));
true
bsh % print(reasoner.getInstances(value1, false));
Nodeset[Node( <http://www.semanticweb.org/ontologies/2011/5/furniture#b> ), Node( <http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#a> )]
bsh % print(reasoner.getInstances(value1, false).getFlattened().size());
2
bsh % print(reasoner.getInstances(value0, false).getFlattened().size());
1
bsh % int count1 = reasoner.getInstances(value1, false).getFlattened().size();
bsh % int count0 = reasoner.getInstances(value0, false).getFlattened().size();
bsh % float percentage = 100.0f * ((float) count1) / ((float) (count0 + count1));
bsh % print(percentage);
66.666664
bsh % OWLDataProperty percentageProperty = factory.getOWLDataProperty(NS + "#percentage_having_final_value_1");
// Error: EvalError: Typed variable declaration : Error in method invocation: Method getOWLDataProperty( java.lang.String ) not found in class'org.protege.owlapi.concurrent.SynchronizedOWLDataFactoryImpl' : at Line: 1 : in file: <unknown file> : factory .getOWLDataProperty ( NS + "#percentage_having_final_value_1" ) 

bsh % OWLDataProperty percentageProperty = factory.getOWLDataProperty(IRI.create(NS + "#percentage_having_final_value_1"));
bsh % print(ontology.containsEntityInSignature(percentageProperty));
true
bsh % print(ontology.getDataPropertyAssertionAxioms(percentageProperty));
// Error: EvalError: Error in method invocation: Method getDataPropertyAssertionAxioms( uk.ac.manchester.cs.owl.owlapi.OWLDataPropertyImpl ) not found in class'uk.ac.manchester.cs.owl.owlapi.OWLOntologyImpl' : at Line: 1 : in file: <unknown file> : ontology .getDataPropertyAssertionAxioms ( percentageProperty ) 

bsh % List changes = new ArrayList();
bsh % manager.applyChanges(changes);
bsh % for (OWLAxiom axiom : ontology.getReferencingAxioms(percentageProperty)) {
if (axiom instanceof OWLDataPropertyAssertionAxiom && ((OWLDataPropertyAssertionAxiom) axiom).getProperty().equals(percentageProperty)) {
changes.add(new RemoveAxiom(ontology, axiom);
// Error: Parser Error: Parse error at line 1, column 10249.  Encountered: (
bsh % if (axiom instanceof OWLDataPropertyAssertionAxiom && ((OWLDataPropertyAssertionAxiom) axiom).getProperty().equals(percentageProperty)) { changes.add(new RemoveAxiom(ontology, axiom)); }
;
bsh % bsh % print(changes);
[]
bsh % Set individuals = new HashSet();
bsh % individuals.addAll(reasoner.getInstances(value1, false).getFlattened());
bsh % print(individuals);
[<http://www.semanticweb.org/ontologies/2011/5/furniture#b>, <http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#a>]
bsh % individuals.addAll(reasoner.getInstances(value0, false).getFlattened());
bsh % print(individuals);
[<http://www.semanticweb.org/ontologies/2011/5/furniture#b>, <http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#a>, <http://www.semanticweb.org/ontologies/2011/5/furniture#d>]
bsh % for (OWLNamedIndividual i : individuals) {
changes.add(new AddAxiom(ontology, factory.getOWLDataFactoryAssertionAxiom(i, percentageProperty, percentage)));
}
// Error: EvalError: Error in method invocation: Method getOWLDataFactoryAssertionAxiom( uk.ac.manchester.cs.owl.owlapi.OWLNamedIndividualImpl, uk.ac.manchester.cs.owl.owlapi.OWLDataPropertyImpl, float ) not found in class'org.protege.owlapi.concurrent.SynchronizedOWLDataFactoryImpl' : at Line: 1 : in file: <unknown file> : factory .getOWLDataFactoryAssertionAxiom ( i , percentageProperty , percentage ) 

bsh % for (OWLNamedIndividual i : individuals) {
changes.add(new AddAxiom(ontology, factory.getOWLDataFactoryAssertionAxiom(percentageProperty, i, percentage)));
}
// Error: EvalError: Error in method invocation: Method getOWLDataFactoryAssertionAxiom( uk.ac.manchester.cs.owl.owlapi.OWLDataPropertyImpl, uk.ac.manchester.cs.owl.owlapi.OWLNamedIndividualImpl, float ) not found in class'org.protege.owlapi.concurrent.SynchronizedOWLDataFactoryImpl' : at Line: 1 : in file: <unknown file> : factory .getOWLDataFactoryAssertionAxiom ( percentageProperty , i , percentage ) 

bsh % for (OWLNamedIndividual i : individuals) {
changes.add(new AddAxiom(ontology, factory.getOWLDataPropertyAssertionAxiom(percentageProperty, i, percentage)));
}
bsh % print (changes);
[ADD AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/furniture#b> "66.666664"^^xsd:float), ADD AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#a> "66.666664"^^xsd:float), ADD AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/furniture#d> "66.666664"^^xsd:float)]
bsh % manager.applyChanges(changes);
bsh % changes.clear();
bsh % % test the remove method
// Error: Parser Error: Parse error at line 1, column 5785.  Encountered: %
bsh % ; test the remove method
bsh % // Error: Parser Error: Parse error at line 1, column 67.  Encountered: remove
bsh %  for (OWLAxiom axiom : ontology.getReferencingAxioms(percentageProperty)) {
if (axiom instanceof OWLDataPropertyAssertionAxiom && ((OWLDataPropertyAssertionAxiom) axiom).getProperty().equals(percentageProperty)) {
changes.add(new RemoveAxiom(ontology, axiom));
}
;
}
bsh % print (changes);
[REMOVE AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#a> "66.666664"^^xsd:float), REMOVE AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/furniture#b> "66.666664"^^xsd:float), REMOVE AXIOM: DataPropertyAssertion(<http://www.semanticweb.org/ontologies/2011/5/Marouns_problem#percentage_having_final_value_1> <http://www.semanticweb.org/ontologies/2011/5/furniture#d> "66.666664"^^xsd:float)]
bsh % manager.applyChanges();
// Error: EvalError: Error in method invocation: Method applyChanges() not found in class'org.protege.owlapi.model.ProtegeOWLOntologyManager' : at Line: 1 : in file: <unknown file> : manager .applyChanges ( ) 

bsh % manager.applyChanges(changes);
bsh % 

Duplicated Axioms

At one point there was some discussion about how Protege should handle axioms that are duplicated in more than one location in the imports closure of a ontology. Obviously this led to a desire to find all the duplicated axioms. The obi ontology is an interesting ontology in this regard - it has several duplicated axioms. I have added some code to ignore the "external" ontologies because these don't really count for this analysis in the obi case. For some reason this bean shell code only works when it is cut and pasted. It does not work when it is run from a script file. I don't know why yet.

import java.util.TreeSet;

print("Starting algorithm");

Set allAxioms = new HashSet();
for (OWLOntology inImportsClosure : mngr.getActiveOntology().getImportsClosure()) {
    if (inImportsClosure.getOntologyID().getOntologyIRI().toString().contains("external")) {
       continue;
    }
    print("Getting axioms from " + inImportsClosure);
    allAxioms.addAll(inImportsClosure.getAxioms());
};

print("Collected " + allAxioms.size() + " from all the ontologies");
for (OWLAxiom axiom : allAxioms) {
    if (axiom instanceof OWLDeclarationAxiom) {
        continue;
    }
    Set ontologies = new TreeSet();
    for (OWLOntology inImportsClosure : mngr.getActiveOntology().getImportsClosure()) {
        if (inImportsClosure.getOntologyID().getOntologyIRI().toString().contains("external")) {
           continue;
        }
        if (inImportsClosure.containsAxiom(axiom)) {
            ontologies.add(inImportsClosure);
        }
    }
    if (ontologies.size() > 1) {
        print("Axiom: " + axiom + " found in the following ontologies:");
        for (OWLOntology ontology : ontologies) {
            print("\t" + ontology);
        }
    }
};

Missing Annotation Properties