2

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>
Mark Miller
  • 3,011
  • 1
  • 14
  • 34
Sabbiu Shah
  • 1,569
  • 3
  • 16
  • 28
  • 1
    This is well written, but it doesn't look like you've attempted a technical solution at all. If I understand your question correctly, then **yes**, SPARQL is exactly the right tool for this. Could you at least write out your triples with A, B and C in Turtle syntax? If you can't do that by hand, you could visually create the relationships in Protege and then save to Turtle. – Mark Miller Jun 21 '17 at 12:33
  • For the instances, I am able to query it well. Everything works well. But, I couldn't find out resources to query the relationship between the classes with SPARQL. Point me to the correct resources. @MarkMiller – Sabbiu Shah Jun 21 '17 at 12:35
  • Okay, I shall edit the question accordingly. – Sabbiu Shah Jun 21 '17 at 12:36
  • 1
    Once you look at the corresponding triples, you should be able to write triple patterns. You know, it's pattern matching, i.e. some parts should be variables that connect the triple patterns. that's how writing a SPARQL query works. – UninformedUser Jun 21 '17 at 12:38
  • @MarkMiller Check the updates – Sabbiu Shah Jun 21 '17 at 12:46
  • Thanks. You know that **classes** generally aren't connected by any property other than `rdfs:subClassOf` or `owl:equivalentClass`, right? I like your visualization, but those sorts of things can really blur the difference between instances and classes. – Mark Miller Jun 21 '17 at 12:49
  • 1
    Well, what about domain and ranges?? – Sabbiu Shah Jun 21 '17 at 12:50
  • @MarkMiller, I don't know if I was clear or not. But, 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. – Sabbiu Shah Jun 21 '17 at 13:00
  • Does your example contain a case of instances from classes A and B connected through an instance of another class? I don't see it. – Mark Miller Jun 21 '17 at 13:04
  • Yes it does. I shall put it there – Sabbiu Shah Jun 21 '17 at 13:05
  • @SabbiuShah You already have the graph. What is so difficult now to put variables on some of the nodes? – UninformedUser Jun 21 '17 at 13:05
  • @MarkMiller Check the update.. I have added the file – Sabbiu Shah Jun 21 '17 at 13:08
  • @AKSW I used this to generate the graph http://vowl.visualdataweb.org/webvowl.html – Sabbiu Shah Jun 21 '17 at 13:08
  • See my answer, it's really basic triple patter nmatching - especially since you have the graph of the schema. – UninformedUser Jun 21 '17 at 13:08
  • What I meant is, you have the graph visualizing the schema. You have nodes and edges. The rest is pretty straightforward – UninformedUser Jun 21 '17 at 13:09
  • By the way, I'd suggest to use camel-case style for naming, e.g. `worksin` -> `worksIn` or `departmentname` -> `departmentName` Makes things more readable and might allow for processing of the URI fragment for the case where you have no human readable data like `rdfs:label`. – UninformedUser Jun 21 '17 at 13:15
  • Okay.. Noted! @AKSW – Sabbiu Shah Jun 21 '17 at 13:19

2 Answers2

2

I don't understand the difficulty if you already have the graph, but to keep it short:

Task 1:

SELECT DISTINCT ?p WHERE {
?p rdfs:domain :A ; # properties having domain :A
   rdfs:range :B    # properties having range :B
}

Task 2:

SELECT DISTINCT ?p1 ?p2 ?cls WHERE {
 ?p1 rdfs:domain :A ;      # properties having domain :A
     rdfs:range ?cls .     # and as range the intermediate class
 ?p2 rdfs:domain ?cls ;    # which is on the other hand the domain of another property
     rdfs:range :C         # that has the range :C
}
UninformedUser
  • 8,397
  • 1
  • 14
  • 23
  • Oh yes! I shall check this.. I was so focused that schema and instance as two different things. I forgot to realize what you were trying to say – Sabbiu Shah Jun 21 '17 at 13:10
  • 1
    For Condition 2, I didn't understand what you meant. If you can clarify, I can add a query. – UninformedUser Jun 21 '17 at 13:11
  • It works! Thanks.. Now, as for condition 2 .. Let's say I have three classes A----(property x)--->B----(property y)--->C, Now given classes A and C, how to figure out a SPARQL query, which helps to find the property x, y and class B are the one's that helps in joining classes A and C. – Sabbiu Shah Jun 21 '17 at 13:18
  • The principle is the same. In the comment you have shown the path, just replace what you want to select by variables and then convert it to triple patterns. – UninformedUser Jun 21 '17 at 13:23
  • 1
    I don't know, my source is mostly the official W3C recommendation - but I guess any good Semantic web lecture should cover the topic SPARQL. – UninformedUser Jun 21 '17 at 13:24
  • Also, What if I don't know the path. It maybe like A----(some property)-->B-->...-->...N--->C. What shall I do in such case? – Sabbiu Shah Jun 21 '17 at 13:30
  • What to query if I want for SPARQL to find out the path between to classes,,, @AKSW – Sabbiu Shah Jun 21 '17 at 13:32
  • I've taken a stab at the unknown path between two instances – Mark Miller Jun 21 '17 at 13:55
  • @SabbiuShah You can use SPARQL 1.1 property paths. Note, SPARQL is not a real graph query language, thus, it has some natural limitations regarding graph traversal etc. – UninformedUser Jun 21 '17 at 21:29
1

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>        |
+-------------------------------------------+-----------------------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+
Mark Miller
  • 3,011
  • 1
  • 14
  • 34
  • Concise explanation, Thanks! – Sabbiu Shah Jun 21 '17 at 14:31
  • The answer from @AKSW is a good choice if you really want to ask about the possible relationships between classes, AND you trust that your `aInst p1 bInst` triples are true to the domain and range of p1. You can also check that with an OWL reasoner. – Mark Miller Jun 21 '17 at 14:37
  • 1
    Later today I'll post a similar answer that uses axiomatic definitions of classes, like *an **instructor** is something that **worksin** a **department*** – Mark Miller Jun 21 '17 at 14:38