Search code examples
sparqlrdfowl

How to query OWL schema for paths between instances


Suppose, I have a class named A (say), and another class named (B) and so on...

Now, I want to find a relation between A and B.

Condition One:

Let's assume they are both connected by a property with domain A and range B.

Now, how do I find out the property, given two classes A and B.

Condition Two:

Let's assume they are both connected by an intermediate class C which is connected by property.

Now, given those two classes, how do I find out intermediate classes and properties?

Does SPARQL helps in this? If or If not, how?

ExampleOWL ontology, created from WebVOWL This is my owl structure.

Now, given the classes "instructor" and "department", using SPARQL, how do I find out that worksin is the property that joins both classes and it is unidirectional/bidirectional?

<!-- OWL Class Definition - Instructor Type -->
<owl:Class rdf:about="http://www.example.com/sample#instructor">

    <rdfs:label>The instructor type</rdfs:label>
    <rdfs:comment>The class of all instructor types.</rdfs:comment>

</owl:Class>

<!-- OWL Class Definition - Department Type -->
<owl:Class rdf:about="http://www.example.com/sample#department">

    <rdfs:label>The department type</rdfs:label>
    <rdfs:comment>The class of all department types.</rdfs:comment>

</owl:Class>



<!-- Define the works in property -->
<owl:ObjectProperty rdf:about="http://www.example.com/sample#worksin">
    <rdfs:domain rdf:resource="http://www.example.com/sample#instructor" />
    <rdfs:range rdf:resource="http://www.example.com/sample#department" />
</owl:ObjectProperty>

Using the following SPARQL query, I am able to retrieve the instances associated with the class. But, how do I find out the property that joins the class.

select ?b where {
     ?b <http://www.example.com/sample#worksin> <http://www.example.com/sample#history>
}

TL;DR What I am actually looking for is, given the classes, I want to find the intermediate classes and properties that joins the classes. So that, I will be able to query for the instances.

Full OWL File

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sample="http://www.example.com/sample#">

    <!-- OWL Header Example -->
    <owl:Ontology rdf:about="http://www.example.com/sample">
        <dc:title>The example.com Example Instructor Ontology</dc:title>
        <dc:description>An example ontolgy for instructor and where he or she works</dc:description>
    </owl:Ontology>

    <!-- OWL Class Definition - Instructor Type -->
    <owl:Class rdf:about="http://www.example.com/sample#instructor">

        <rdfs:label>The instructor type</rdfs:label>
        <rdfs:comment>The class of all instructor types.</rdfs:comment>

    </owl:Class>

    <!-- OWL Class Definition - Department Type -->
    <owl:Class rdf:about="http://www.example.com/sample#department">

        <rdfs:label>The department type</rdfs:label>
        <rdfs:comment>The class of all department types.</rdfs:comment>

    </owl:Class>


    <!-- Define the instructor name property -->
    <owl:DatatypeProperty rdf:about="http://www.example.com/sample#instructorname">
        <rdfs:domain rdf:resource="http://www.example.com/sample#instructor" />
    </owl:DatatypeProperty>

    <!-- Define the salary property -->
    <owl:DatatypeProperty rdf:about="http://www.example.com/sample#salary">
        <rdfs:domain rdf:resource="http://www.example.com/sample#instructor" />
    </owl:DatatypeProperty>

    <!-- Define the department name property -->
    <owl:DatatypeProperty rdf:about="http://www.example.com/sample#departmentname">
        <rdfs:domain rdf:resource="http://www.example.com/sample#department" />
    </owl:DatatypeProperty>


    <!-- Define the building property -->
    <owl:DatatypeProperty rdf:about="http://www.example.com/sample#building">
        <rdfs:domain rdf:resource="http://www.example.com/sample#department" />
    </owl:DatatypeProperty>

    <!-- Define the budget property -->
    <owl:DatatypeProperty rdf:about="http://www.example.com/sample#budget">
        <rdfs:domain rdf:resource="http://www.example.com/sample#department" />
    </owl:DatatypeProperty>

    <!-- Define the works in property -->
    <owl:ObjectProperty rdf:about="http://www.example.com/sample#worksin">
        <rdfs:domain rdf:resource="http://www.example.com/sample#instructor" />
        <rdfs:range rdf:resource="http://www.example.com/sample#department" />
    </owl:ObjectProperty>


    <!-- Define the Einstein class instance -->
    <rdf:Description rdf:about="http://www.example.com/sample#einstein">

        <!-- Einstein is an individual (instance) of the instructor class -->
        <rdf:type rdf:resource="http://www.example.com/sample#instructor"/>

        <!-- Einstein name stored under -->
        <sample:instructorname>Einstein</sample:instructorname>

        <!-- Einstein earns 95000 -->
        <sample:salary>95000</sample:salary>

        <!-- Einstein works in Physics Department -->
        <sample:worksin rdf:resource="http://www.example.com/sample#physics"/>

    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#wu">
        <rdf:type rdf:resource="http://www.example.com/sample#instructor"/>
        <sample:instructorname>Wu</sample:instructorname>
        <sample:salary>90000</sample:salary>
        <sample:worksin rdf:resource="http://www.example.com/sample#finance"/>
    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#singh">
        <rdf:type rdf:resource="http://www.example.com/sample#instructor"/>
        <sample:instructorname>Singh</sample:instructorname>
        <sample:salary>80000</sample:salary>
        <sample:worksin rdf:resource="http://www.example.com/sample#finance"/>
    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#elsaid">
        <rdf:type rdf:resource="http://www.example.com/sample#instructor"/>
        <sample:instructorname>El Said</sample:instructorname>
        <sample:salary>60000</sample:salary>
        <sample:worksin rdf:resource="http://www.example.com/sample#history"/>
    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#califieri">
        <rdf:type rdf:resource="http://www.example.com/sample#instructor"/>
        <sample:instructorname>Califieri</sample:instructorname>
        <sample:salary>62000</sample:salary>
        <sample:worksin rdf:resource="http://www.example.com/sample#history"/>
    </rdf:Description>

    <!-- Now for department table -->
    <rdf:Description rdf:about="http://www.example.com/sample#physics">
        <rdf:type rdf:resource="http://www.example.com/sample#department"/>
        <sample:departmentname>Physics</sample:departmentname>
        <sample:building>Watson</sample:building>
        <sample:budget>70000</sample:budget>
    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#finance">
        <rdf:type rdf:resource="http://www.example.com/sample#department"/>
        <sample:departmentname>Finance</sample:departmentname>
        <sample:building>Painter</sample:building>
        <sample:budget>120000</sample:budget>
    </rdf:Description>

    <rdf:Description rdf:about="http://www.example.com/sample#history">
        <rdf:type rdf:resource="http://www.example.com/sample#department"/>
        <sample:departmentname>History</sample:departmentname>
        <sample:building>Painter</sample:building>
        <sample:budget>50000</sample:budget>
    </rdf:Description>

</rdf:RDF>

Solution

  • If you add a hasWorker property as the inverse of worksin, and you use a triplestore with owl reasoning, you could use something like the following query for relationships like

    A p1 B p2 C
    

    Really generalizing this for any number of hops and any choice of properties is really hard: path between two resources

    triples:

    @prefix owl: <http://www.w3.org/2002/07/owl#> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    @prefix ns0: <http://www.example.com/sample#> .
    
    <http://www.example.com/sample#worksin>
      a owl:ObjectProperty ;
      owl:inverseOf <http://www.example.com/sample/hasWorker> ;
      rdfs:domain <http://www.example.com/sample#instructor> ;
      rdfs:range <http://www.example.com/sample#department> .
    
    <http://www.example.com/sample/hasWorker> a owl:ObjectProperty .
    <http://www.example.com/sample#departmentname>
      a owl:DatatypeProperty ;
      rdfs:domain <http://www.example.com/sample#department> .
    
    <http://www.example.com/sample#instructorname>
      a owl:DatatypeProperty ;
      rdfs:domain <http://www.example.com/sample#instructor> .
    
    <http://www.example.com/sample#department> a owl:Class .
    <http://www.example.com/sample#instructor> a owl:Class .
    <http://www.example.com/sample#califieri>
      a owl:NamedIndividual, <http://www.example.com/sample#instructor> ;
      ns0:worksin ns0:history ;
      ns0:instructorname "Califieri" .
    
    ns0:einstein
      a owl:NamedIndividual, ns0:instructor ;
      ns0:worksin ns0:physics ;
      ns0:instructorname "Einstein" .
    
    ns0:elsaid
      a owl:NamedIndividual, ns0:instructor ;
      ns0:worksin ns0:history ;
      ns0:instructorname "El Said" .
    
    ns0:finance
      a owl:NamedIndividual, ns0:department ;
      ns0:departmentname "Finance" .
    
    ns0:history
      a owl:NamedIndividual, ns0:department ;
      ns0:departmentname "History" .
    
    ns0:physics
      a owl:NamedIndividual, ns0:department ;
      ns0:departmentname "Physics" .
    
    ns0:singh
      a owl:NamedIndividual, ns0:instructor ;
      ns0:worksin ns0:finance ;
      ns0:instructorname "Singh" .
    
    ns0:wu
      a owl:NamedIndividual, ns0:instructor ;
      ns0:worksin ns0:finance ;
      ns0:instructorname "Wu" .
    

    query:

    SELECT DISTINCT  ?aInst ?p1 ?bInst ?p2 ?cInst 
    WHERE
    {
      ?aInst  a                     ?a .
      ?a a owl:Class .
    
      ?bInst  a                     ?b .
      ?b a owl:Class .
    
      ?cInst  a                     ?c .
      ?c a owl:Class .
    
      ?aInst  ?p1                   ?bInst .
      ?bInst  ?p2                   ?cInst
    
      filter (?aInst != ?bInst )
      filter (?bInst != ?cInst )
      filter (?aInst != ?cInst )
    
      filter (?p1 != <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> )
    
      filter (?p2 != <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> )
    }
    

    Result:

    +-------------------------------------------+-----------------------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+
    |                   aInst                   |                   p1                    |                  bInst                  |                    p2                     |                   cInst                   |
    +-------------------------------------------+-----------------------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+
    | <http://www.example.com/sample#elsaid>    | <http://www.example.com/sample#worksin> | <http://www.example.com/sample#history> | <http://www.example.com/sample/hasWorker> | <http://www.example.com/sample#califieri> |
    | <http://www.example.com/sample#califieri> | <http://www.example.com/sample#worksin> | <http://www.example.com/sample#history> | <http://www.example.com/sample/hasWorker> | <http://www.example.com/sample#elsaid>    |
    | <http://www.example.com/sample#wu>        | <http://www.example.com/sample#worksin> | <http://www.example.com/sample#finance> | <http://www.example.com/sample/hasWorker> | <http://www.example.com/sample#singh>     |
    | <http://www.example.com/sample#singh>     | <http://www.example.com/sample#worksin> | <http://www.example.com/sample#finance> | <http://www.example.com/sample/hasWorker> | <http://www.example.com/sample#wu>        |
    +-------------------------------------------+-----------------------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+