Search code examples
pythonsparqlrdfowlrdflib

get the intersected classes in SPARQL query using RDFLib


I have a class ABC that is a subClassOf the class XYZ and defined as intersections of classes A, B, C as:

<Class rdf:about="&clink;ABC">
    <equivalentClass>
        <Class>
            <intersectionOf rdf:parseType="Collection">
                <Restriction>
                    <onProperty rdf:resource="&clink;affects"/>
                    <someValuesFrom rdf:resource="&clink;A"/>
                </Restriction>
                <Restriction>
                    <onProperty rdf:resource="&clink;hasMarker"/>
                    <someValuesFrom rdf:resource="&clink;B"/>
                </Restriction>
                <Restriction>
                    <onProperty rdf:resource="&clink;hasPathologicalProcess"/>
                    <someValuesFrom rdf:resource="&clink;C"/>
                </Restriction>
            </intersectionOf>
        </Class>
    </equivalentClass>
    <rdfs:subClassOf rdf:resource="&clink;XYZ"/>
</Class>

How I can get access to the classes A, B and C through the class XYZ using SPARQL query in RDFLib?

The following query returns a blank node rdflib.term.BNode('_L') and I don't know how to handle the BNodes.

PREFIX rdf: h<ttp://www.w3.org/2000/01/rdf-schema#>

SELECT ?subclass
WHERE {<XYZ> <rdf:subClassOf> <subclass>} 

I need a query that receive the XYZ and returns this:

A
B
C

Solution

  • First of all, XYZ is neither a subClassOf A, B, C nor a subClassOf their intersection A and B and C (I am using manchester syntaax (see here)).

    In your snippet, you define XYZ to be equivalentTo (which implies being a subClassOf as well) of the intersection of three anynomous (see here) classes; which are (affects some A) and (hasMaker some B) and (hasPathologicalProcess some C). This intersection is not equivalent to A and B and C (some in Manchester syntax stands for someValuesFrom).

    To understand what someValuesFrom restriction means, see the documentation (see here) of OWL:

    The value constraint owl:someValuesFrom is a built-in OWL property that links a restriction class to a class description or a data range. A restriction containing an owl:someValuesFrom constraint describes a class of all individuals for which at least one value of the property concerned is an instance of the class description or a data value in the data range. In other words, it defines a class of individuals x for which there is at least one y (either an instance of the class description or value of the data range) such that the pair (x,y) is an instance of P. This does not exclude that there are other instances (x,y') of P for which y' does not belong to the class description or data range.

    EDIT2:

    Now that you should have understood what owl:someValuesFrom means, and as @AKSW suggests, here is a straightforward SPARQL query. However, you cannot retrieve A, B, and C simply using rdfs:subClassOf! You should first retrieve the restriction, then access the property and the class it is defined on, as follows:

    prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
    prefix owl:   <http://www.w3.org/2002/07/owl#>
    prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    
    select ?eqclass ?restriction ?onProp  ?someValuesFrom where {
    
      {?eqclass owl:equivalentClass/owl:intersectionOf _:b. _:b rdf:first ?restriction}
      # First anonymous class (restriction) in the collection
      UNION { ?eqclass owl:equivalentClass/owl:intersectionOf/(rdf:rest+/rdf:first+)*  ?restriction.} 
      # getting other anonymous classes (restriction) using property paths and rdf:first and rdf:rest used in RDF collections.       
      ?restriction  rdf:type owl:Restriction. 
      # individuals of type owl:Restriction
      ?restriction  owl:onProperty ?onProp. 
      # the property the restriciton is defined on which
      ?restriction  owl:someValuesFrom ?someValuesFrom.
      # the class of the owl:someValuesFrom property
    } 
    

    End of EDIT2

    Other work around through modifying your data model.

    So first, your query should return the anonymous class (affects some A) and (hasMaker some B) and (hasPathologicalProcess some C) which is the intersection you define. However, as it is an anonymous class, a blank node B_node will be returned for it, rather than a concrete class. To return a concrete class, you should define this anonymous intersection as a class in your ontology for this intersection; for example, you can create the class anyn_intersection, as follows:

    <owl:Class rdf:about="myPrefix#anyn_intersection">
        <owl:equivalentClass>
            <owl:Class>
                <owl:intersectionOf rdf:parseType="Collection">
                    <owl:Restriction>
                        <owl:onProperty rdf:resource="myPrefix#affects"/>
                        <owl:someValuesFrom rdf:resource="myPrefix#A"/>
                    </owl:Restriction>
                    <owl:Restriction>
                        <owl:onProperty rdf:resource="myPrefix#hasMaker"/>
                        <owl:someValuesFrom rdf:resource="myPrefix#B"/>
                    </owl:Restriction>
                    <owl:Restriction>
                        <owl:onProperty rdf:resource="myPrefix#hasPathologicalProcess"/>
                        <owl:someValuesFrom rdf:resource="myPrefix#C"/>
                    </owl:Restriction>
                </owl:intersectionOf>
            </owl:Class>
        </owl:equivalentClass>
    </owl:Class>
    

    Thus, your query will get this class anyn_intersection instead of the blank node.

    Now If you want to get all of (affects some A), (hasMaker some B), and (hasPathologicalProcess some C) in the results, you should first make sure that a reasoner is running because this is an implicit knowledge and second you should for each anonymous intersection class, define a concrete intersection class in a similar way to the anyn_intersection above. For example, you can define anyn_AffectsSomeA for the anonymous restriction class: affects some A as follows:

    <owl:Class rdf:about="myPrefix#anyn_AffectsSomeA">
        <owl:equivalentClass>
            <owl:Restriction>
                <owl:onProperty rdf:resource="myPrefix#affects"/>
                <owl:someValuesFrom rdf:resource="myPrefix#A"/>
            </owl:Restriction>
        </owl:equivalentClass>
    </owl:Class>
    

    Then you have to define two similar classes anyn_hasMakerSomeB and anyn_hasPathologicalProcessSomeC. Finally, you define anyn_intersection as the intersection of anyn_AffectsSomeA, anyn_hasMakerSomeB, and anyn_hasPathologicalProcessSomeC.

    EDIT1:

    I am not aware if there is some specific feature in rdfLib that enables you to retrieve anonymous classes definitions. That might solve your problem without having to define it the way I suggest. Additionally, you should make sure a reasoner is running.

    End of EDIT1: