Search code examples
sparqlowlrdfs

SPARQL: how to transfer owl:equivalentClass to rdfs:subClassOf (owl:Restriction) properties?


My question is about using SPARQL to query some owl ontology where owl:Restrictions are heavily used (in my case this is the "Cell Ontology").

Here is an example of some typical entry (in Turtle format, extracted from the above mentioned ontology):

###  http://purl.obolibrary.org/obo/CL_0000792
obo:CL_0000792 rdf:type owl:Class ;
           owl:equivalentClass [ owl:intersectionOf ( obo:CL_0000624
                                                      [ rdf:type owl:Restriction ;
                                                        owl:onProperty obo:RO_0002104 ;
                                                        owl:someValuesFrom obo:PR_000001380
                                                      ]
                                                      [ rdf:type owl:Restriction ;
                                                        owl:onProperty obo:RO_0002215 ;
                                                        owl:someValuesFrom obo:GO_0050777
                                                      ]
                                                      [ rdf:type owl:Restriction ;
                                                        owl:onProperty <http://purl.obolibrary.org/obo/cl#has_low_plasma_membrane_amount> ;
                                                        owl:someValuesFrom obo:PR_000001869
                                                      ]
                                                    ) ;
                                 rdf:type owl:Class
                               ] ;
           rdfs:subClassOf obo:CL_0000624 ,
                           obo:CL_0000815 ,
                           [ rdf:type owl:Restriction ;
                             owl:onProperty obo:RO_0002104 ;
                             owl:someValuesFrom obo:PR_000001380
                           ] ,
                           [ rdf:type owl:Restriction ;
                             owl:onProperty obo:RO_0002215 ;
                             owl:someValuesFrom obo:GO_0050777
                           ] ,
                           [ rdf:type owl:Restriction ;
                             owl:onProperty <http://purl.obolibrary.org/obo/cl#has_low_plasma_membrane_amount> ;
                             owl:someValuesFrom obo:PR_000001869
                           ] .

Here my ultimate goal is to transfer the owl equivalent properties to subClassOf properties:

CL_0000792 rdfs:subClassOf [
     rdf:type owl:Restriction ;
              owl:onProperty obo:RO_0002104 ;
              owl:someValueFrom obo:PR_000001380
 ] ;
 rdfs:subClassOf [
     rdf:type owl:Restriction ;
              owl:onProperty obo:cl#has_low_plasma_membrane_amount ;
              owl:someValueFrom obo:PR_000001869
 ] .

What I do not achieve is to obtain all three properties from the rdfs:subclass part and then bind them properly to the subClassOf sorts of properties (then filtering out the obo:RO_0002215 would be easy).

EDIT: As I made some progress here a new SPARQL Query

EDIT2: following Damyan Ognyanov's answer updated the SPARQL query part which was ignoring the collection within the owl:intersectionOf part and which also more compact/elegant

Here my current SPARQL query:

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX obo: <http://purl.obolibrary.org/obo/>
PREFIX tpo: <http://www.definiens.com/ontologies/TissuePhenomicsOntology>
PREFIX cl: <http://purl.obolibrary.org/obo/cl.owl>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX efo: <http://www.ebi.ac.uk/efo/efo.owl>

CONSTRUCT {
    ?cell rdfs:subClassOf [ rdf:type owl:Restriction ;
                            owl:onProperty ?cellProp ;
                            owl:someValuesFrom ?cellPropValue
                            ] .
    ?cellProp ?cellPropProp ?cellPropObj .
    ?cellPropValue ?cellPropValueProp ?cellPropValuePropValue .
    ?cell ?cellProp2 ?cellProp2Obj .
}

FROM named cl:
FROM named tpo:
WHERE {
    # query cl to get our information
    graph cl:
    {   
       ?cell (rdfs:subClassOf|(owl:equivalentClass/owl:intersectionOf/rdf:rest*/rdf:first)) ?x .
       ?x owl:onProperty ?cellProp ;
          owl:someValuesFrom ?cellPropValue .

        ?cellProp ?cellPropProp ?cellPropObj . 
        ?cellPropValue ?cellPropValueProp ?cellPropValuePropValue .
        ?cell ?cellProp2 ?cellProp2Obj .
    }

    # limit ?cell to the entries already present in TPO
    graph tpo:
    {
        ?cell rdfs:subClassOf* obo:CL_0000000 .
    }
}    

If you replace the CONSTRUCT part with a SELECT * then it appears that all variables are correctly assigned, the information is there.

What I am still missing though is a proper CONSTRUCT part to reconstruct the "somewhat convoluted" owl:Property restriction. As such this query mostly returns a long list of blank nodes, which won't be parsed properly by Protege for instance.

@AKSW also rightly pointed out that SPARQL may not be the tool of choice to query and construct OWL graphs. It indeed appears clearly here that one needs to know the precise data structure in order to build a working query, in this manner at least.

?cell (rdfs:subClassOf|(owl:equivalentClass/owl:intersectionOf/rdf:rest*/rdf:first)) ?x . ?x owl:onProperty ?cellProp ; owl:someValuesFrom ?cellPropValue .

?cellProp ?cellPropProp ?cellPropObj . ?cellPropValue ?cellPropValueProp ?cellPropValuePropValue . ?cell ?cellProp2 ?cellProp2Obj .


Solution

  • The value of owl:intersectionOf is an RDF list and the above Turtle snippet uses the RDF list syntax to enumerate the members of the owl:intersectionOf collection (e.g., entries are enclosed between ( and )).

    So, you should also include rdf:rest*/rdf:first properties in your property paths, since these are used to construct the collection.

    For the query, I'll introduce an additional variable where to bind the restriction of interest and use it to fetch the values of owl:onProperty and owl:someValuesFrom, e.g., your WHERE clause may look something like:

    ?cell (rdfs:subClassOf|(owl:equivalentClass/owl:intersectionOf/rdf:rest*/rdf:first)) ?x .
    ?x owl:onProperty ?cellProp ;
       owl:someValuesFrom ?cellPropValue .
    
    ?cellProp ?cellPropProp ?cellPropObj . 
    ?cellPropValue ?cellPropValueProp ?cellPropValuePropValue .
    ?cell ?cellProp2 ?cellProp2Obj .