SmartDataAnalytics / OWL2SPARQL

OWL To SPARQL Query Rewriter
Apache License 2.0
20 stars 8 forks source link

Enhancement: Support for ABox axioms #3

Open dlutz2 opened 7 years ago

dlutz2 commented 7 years ago

Is support for ABox axioms planned? Individuals in class expressions seem to be supported. Or am I missing something? thanks

LorenzBuehmann commented 6 years ago

While class expressions describe sets of individuals than can be queried via SPARQL SELECT queries, it's not clear what queries you expect to get for ABox axioms.

Maybe we should generate SPARQL ASK queries in that case?

turbomam commented 6 years ago

I would find class expression -> SPARQL rewriting helpful, too. Maybe that's because I make punning statements? For example, I need to find all drug prescription individuals that mention any drug tablet that (indirectly) has the drug 'rosuvastatin' as an active ingredient

X a 'drug prescription' http://purl.obolibrary.org/obo/PDRO_0000024 X mentions 'rosuvastatin Oral Tablet' http://purl.obolibrary.org/obo/DRON_00027869

'rosuvastatin Oral Tablet' Superclasses & Asserted Axioms: drug tablet has_proper_part some (scattered molecular aggregate and (is bearer of some active ingredient) and (has granular part some rosuvastatin))

where rosuvastatin is http://purl.obolibrary.org/obo/DRON_00018679

See also https://stackoverflow.com/questions/51001818/rewrite-owl-class-expression-as-sparql-query

Copied from StackOverflow question

The example code:

var ce2s = new OWLClassExpressionToSPARQLConverter()

var a2s = new OWLAxiomToSPARQLConverter("?s", "?o")

var preManager = new OWLManager
var manager = OWLManager.createOWLOntologyManager()

var ontology = manager.loadOntologyFromOntologyDocument(new File("animals.owl"))

var factory = manager.getOWLDataFactory()
var iri = IRI.create("http://example.com/carnivore")

var someClass = factory.getOWLClass(iri)

var declarationAxiom = factory.getOWLDeclarationAxiom(someClass)

println(declarationAxiom)

var asSparql = a2s.convert(declarationAxiom, "?s", "?o")

example ontology:

Ontology: <http://example.com/animals.owl>

ObjectProperty: <http://example.com/eats>

Class: <http://example.com/animal>

Class: <http://example.com/carnivore>

    EquivalentTo: 
    <http://example.com/eats> some <http://example.com/animal>

    SubClassOf: 
    <http://example.com/animal>

example output:

sbt:hello> run
[info] Packaging /home/mark/owl2sparql4turbo/target/scala-2.10/hello_2.10-1.0.jar ...
[info] Done packaging.
[info] Running HelloWorld 
Declaration(Class(<http://example.com/carnivore>))

with the warning

0 [run-main-0] WARN org.aksw.owl2sparql.OWLAxiomToSPARQLConverter - Ignoring axiom Declaration(Class(http://example.com/carnivore)) . Reason: Annotation axioms are not supported. [success] Total time: 1 s, completed Jun 23, 2018 10:33:33 AM

expected output:

select ?s
where
{
    ?s rdfs:subClassOf <http://example.com/animal>  ?r .
    ?r a owl:Restriction ;
        owl:onProperty <http://example.com/eats> ;
        owl:someValuesFrom <http://example.com/animal> .
}
LorenzBuehmann commented 6 years ago

Thank you for the request. Will check tomorrow what's not working as expected.

LorenzBuehmann commented 6 years ago

@turbomam Regarding your example, an OWL declaration axiom is just a statement about the type of the entity. It doesn't contain any meaningful but just declares the existence and the type. In the ontology two axioms do exist, you'd have to use one of those axioms as input.

I added an experimental converter from an OWL class expression to a SPARQL query that retrieves subclasses: https://github.com/SmartDataAnalytics/OWL2SPARQL/blob/develop/src/main/java/org/aksw/owl2sparql/OWLClassExpressionToSPARQLSubClassQueryConverter.java

Right now, it is only in the develop branch and of course it's missing documentation.

You'll need 0.2-SNAPSHOT version as dependency.

Not sure whether this is what you need, but you could check with your use-case and let me know what's missing resp. is what's wrong.

Usage:

OWLClassExpressionToSPARQLSubClassQueryConverter converter = new OWLClassExpressionToSPARQLSubClassQueryConverter();

String targetVar = "?x";

OWLClassExpression ce = ...

// with more compact notation of blank nodes
String queryStr = converter.convert(ce, targetVar);

// alternatively, the Jena query object
Query query = converter.asQuery(ce, targetVar);
turbomam commented 6 years ago

Thanks. It's possible that you have provided exactly what I was asking for, but I can't seem to get it to write a query for anything besides ?x rdfs:SubClassOf ?x

animals.owl

Prefix: owl: <http://www.w3.org/2002/07/owl#>
Prefix: rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
Prefix: rdfs: <http://www.w3.org/2000/01/rdf-schema#>
Prefix: xml: <http://www.w3.org/XML/1998/namespace>
Prefix: xsd: <http://www.w3.org/2001/XMLSchema#>

Ontology: <http://example.com/animals.owl>

ObjectProperty: <http://example.com/eats>

Class: <http://example.com/animal>

Class: <http://example.com/carnivore>

    SubClassOf: 
        <http://example.com/animal>
         and (<http://example.com/eats> some <http://example.com/animal>)

Scala script

import org.aksw.owl2sparql._
import org.semanticweb.owlapi.apibinding.OWLManager
import org.semanticweb.owlapi.model.IRI
import java.io.File

object HelloWorld {
  def main(args: Array[String]): Unit = {

    var manager = OWLManager.createOWLOntologyManager()
    var ontology = manager.loadOntologyFromOntologyDocument(new File("animals.owl"))

    var factory = manager.getOWLDataFactory()
    var iri = IRI.create("http://example.com/carnivore")
    var someClass = factory.getOWLClass(iri)

    var declarationAxiom = factory.getOWLDeclarationAxiom(someClass)

    var scConverter = new OWLClassExpressionToSPARQLSubClassQueryConverter();

    var targetVar = "?x";

    var queryStr = scConverter.convert(someClass, targetVar)

    println(queryStr)

  }
}

actual output

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT ?x WHERE {  ?x rdf:type owl:Class ;
     rdfs:subClassOf <http://example.com/carnivore> .
}

expected/desire output

select ?s
where
{
    ?s rdfs:SubClassOf <http://example.com/animal> , ?r .
    ?r a owl:Restriction ;
        owl:onProperty <http://example.com/eats> ;
        owl:someValuesFrom <http://example.com/animal> .
}
LorenzBuehmann commented 6 years ago

As I said before, a declaration axiom is just a statement about the type and existence of an entity, see the W3C documentation. That's why

factory.getOWLDeclarationAxiom(someClass)

is not what I guess you expect. First of all, you're using the datafactory, thus, it's creating a new axiom and not querying existing axioms in the ontology (doesn't matter in this case, but for others it would - clearly you're interested in axioms contained in the ontology). In your example,

Class: <http://example.com/animal>

is a declaration axiom, just stating that there is an OWL class called http://example.com/animal.

An OWL ontology consists of a set of OWL axioms. What you'd need in your example is to get the superclass of http://example.com/carnivore - and indeed that's defined in a SubClassOf axiom here (might also be defined by means of an EquivalentClasses axiom). Note, there might be multiple axioms!

OWL API provides access to what you want by

1) the OWLOntology object with getSubClassAxiomsForSubClass(OWLClass cls) method - in this case you'll get axioms and have to extract the superclasses by yourself 2) EntitySearcher.getSuperClasses(OWLClass e, OWLOntology ontology) - here you'll get class expressions. as a warning, this won't cover class expressions in EquivalentClasses axioms 3) StructuralReasoner with getSuperClasses(OWLClassExpression ce, boolean direct)

turbomam commented 6 years ago

Thanks, your feedback was very helpful.

I have switched my example (https://github.com/turbomam/owl2sparql4turbo, specifially https://github.com/turbomam/owl2sparql4turbo/blob/master/src/main/scala/ROTS.scala) from using an extremely short ontology about animals to a slightly longer ontology about my real problem, drug tablets.

Now I get the kind of output I hoped for:

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT ?x WHERE {  ?x rdf:type owl:Class ;
     rdfs:subClassOf [ rdf:type owl:Restriction ;
                       owl:onProperty <http://www.obofoundry.org/ro/ro.owl#has_proper_part> ;
                       owl:someValuesFrom [ owl:intersectionOf ( <http://purl.obolibrary.org/obo/OBI_0000576>
                                                                 [ rdf:type owl:Restriction ;
                                                                   owl:onProperty <http://purl.obolibrary.org/obo/BFO_0000053> ;
                                                                   owl:someValuesFrom <http://purl.obolibrary.org/obo/DRON_00000029>
                                                                 ]
                                                                 [ rdf:type owl:Restriction ;
                                                                   owl:onProperty <http://purl.obolibrary.org/obo/BFO_0000071> ;
                                                                   owl:someValuesFrom <http://purl.obolibrary.org/obo/CHEBI_30618>
                                                                 ]
                                                               ) ;
                                            rdf:type owl:Class
                                          ]
                     ] .
}

for an input like

...

Class: obo:DRON_00027869

    Annotations: 
        rdfs:label "rosuvastatin Oral Tablet"^^xsd:string,
        obo:DRON_00010000 "402354"^^xsd:string

    SubClassOf: 
        obo:DRON_00000022,
        <http://www.obofoundry.org/ro/ro.owl#has_proper_part> some 
            (obo:OBI_0000576
             and (obo:BFO_0000053 some obo:DRON_00000028)
             and (obo:BFO_0000071 some obo:DRON_00018679))
...