3

I want to query all subclass of Nicotine (product).
the result must be (Nasal form nicotine, Oropharyngeal from ni ..(4 items).. see in the picture) i try to query by rdfs:subClassOf+ and owl:equivalentClass+ but didn't work try from this example the code same here.

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>           
PREFIX owl: <http://www.w3.org/2002/07/owl#>        
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>         
SELECT * WHERE 
{       
  ?s owl:equivalentClass+ ?o . # and try   ?s rdfs:subClassOf ?o    
  filter(?s=<http://snomed.info/id/323283001>)       
}

this image from protege Thank.

The first query hard to explain and to do because so large file some IRI not subClass and not equivalent class, I change the way to query from this instead

<owl:Class rdf:about="http://snomed.info/id/323283001">
    <rdfs:label xml:lang="en">Nicotine (product)</rdfs:label>
    <rdfs:subClassOf>
        <owl:Class>
            <owl:intersectionOf rdf:parseType="Collection">
                <rdf:Description rdf:about="http://snomed.info/id/420383004"/>
                <rdf:Description rdf:about="http://snomed.info/id/425288007"/>
                <owl:Restriction>
                    <owl:onProperty rdf:resource="http://snomed.info/id/127489000"/>
                    <owl:someValuesFrom rdf:resource="http://snomed.info/id/68540007"/>
                </owl:Restriction>
            </owl:intersectionOf>
        </owl:Class>
    </rdfs:subClassOf>
</owl:Class>

I want to query all id(id/420383004, id/425288007, id/127489000 and id/68540007)

from owl:Class rdf:about="http://snomed.info/id/323283001" please tell me some of idea. Thank

Community
  • 1
  • 1
user3190242
  • 55
  • 1
  • 5
  • I'm not having any luck viewing that image. Could you use, perhaps, imgur? Then someone with enough reputation can update your question to include the picture properly. – Joshua Taylor Jan 13 '14 at 16:20
  • Ah, thank you for posting that update. Notice that there's no triple `http://snomed.info/id/323283001 rdfs:subClassOf http://snomed.info/id/420383004` in the data, even though former is a subclass of the latter. The plain intersection classes you can get, though, by using a slightly more complicated SPARQL query. I'll update my answer. However, it doesn't make sense to ask for `http://snomed.info/id/127489000`, since it's a property, and it doesn't make sense to ask for `http://snomed.info/id/68540007` since, even though it's a class, nicotine isn't a subclass of it. – Joshua Taylor Jan 13 '14 at 18:51
  • thank. We can discard id/127489000 and id/68540007 to the query. – user3190242 Jan 13 '14 at 19:05

1 Answers1

14

First, a couple of notes about your SPARQL query are in order. The first regards the difference between * and + in a property path, and the second regards the use of filter and of values. Then we can look at how to query for different types of subclass/superclass relationships from the data. The trick here is that some of the relationships that we're looking for are relationship that we would typically use an OWL reasoner for, but we're trying to do a bit of that OWL reasoning using SPARQL

A few notes about the original query

Property Paths, + and *

Note that in the other question that you linked to, the property path uses the * operator, which means a path of length zero or more. The path of length zero or more can be pretty important, because if you don't have an explicit triple in your data of the form

:MyClass owl:equivalentClass :MyClass

you won't get any matches for a query

?myClass owl:equivalentClass+ :MyClass

but you will get a result (:MyClass) for

?myClass owl:equivalentClass* :MyClass

Actually, even though owl:equivalentClass is a symmetric property (i.e., from a owl:equivalentClass b we can infer b owl:equivalentClass a), the triple might be present in only one direction in the data, so we'd actually need

?myClass (owl:equivalentClass|^owl:equivalentClass)* :MyClass

Using values instead of filter

As an aside, note that in this query I used the IRI in the pattern directly; there's no need to filter as in your original code:

filter(?s=<http://snomed.info/id/323283001>)

If you do want to bind a variable to the superclass, it's easier to do it with values, as in

values ?superclass { <http://snomed.info/id/323283001> }
?subclass (rdfs:subClassOf|owl:equivalentClass)* ?superclass

OWL Reasoning through SPARQL queries

In general, the relationships between classes (e.g., subclass and superclass relationships) are things that you'd use an OWL reasoner to determine for you. However, some are simple enough and present in the RDF encoding of the OWL axioms that you can draw the same conclusions using a SPARQL query. For instance, if you want to find subclass relationships in a hierarchy based on rdfs:subClassOf and owl:equivalentClass, you can use a pattern like this one:

?subclass (rdfs:subClassOf|owl:equivalentClass|^owl:equivalentClass)* ?superclass

Now, as noted below, you may run into some issues with Protégé's SPARQL tab, so I'd suggest that you keep the | usage to the binary case, so you'd actually write, in this case:

?subclass (rdfs:subClassOf|(owl:equivalentClass|^owl:equivalentClass))* ?superclass

Now, the data that you're actually looking at uses more complicated class expressions. When you have an OWL axiom of the form

A subClassOf (B and C)

what you're actually saying is that there is a class A, and there is a (typically anonymous) class that is an intersection class, and that it is the intersection of B and C. You don't have the axioms

A subClassOf B
A subClassOf C

available to you, although they do logically follow. The case you've got actually includes an existential restriction as well, along the lines of

A subClassOf (B and C and (p some D))

It's important to note that A's superclasses here are B, C, and (p some D). In particular, A is not a subclass of p or D. This might be easier to see with a concrete example:

TiredManWearingHat subClassOf (Man and TiredPerson and (wearing some Hat)

A tired man wearing a hat is clearly a man, is clearly a tired person, and is clearly something that is wearing a hat, but he is most certainly not a wearing (which doesn't even make sense), and he's certainly not a Hat. Here's an minimal ontology that has exactly that structure that we can work with:

simple structure in Protégé

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns="https://stackoverflow.com/q/21092246/1281433/data.owl#">
  <owl:Ontology rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl"/>
  <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#C"/>
  <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#B"/>
  <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#A">
    <rdfs:subClassOf>
      <owl:Class>
        <owl:intersectionOf rdf:parseType="Collection">
          <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#B"/>
          <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#C"/>
          <owl:Restriction>
            <owl:onProperty>
              <owl:ObjectProperty rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#p"/>
            </owl:onProperty>
            <owl:someValuesFrom>
              <owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#D"/>
            </owl:someValuesFrom>
          </owl:Restriction>
        </owl:intersectionOf>
      </owl:Class>
    </rdfs:subClassOf>
  </owl:Class>
</rdf:RDF>

I've already written an answer to Retrieving superclasses implied by OWL intersection classes that described how you can write a query about intersection classes, so I won't explain all of it here again, but I'll include a query that works for this case. The result I'm showing are what I got using Jena's command line SPARQL query tools.

prefix :      <https://stackoverflow.com/q/21092246/1281433/data.owl#> 
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 ?superclass where {
  :A (rdfs:subClassOf|(owl:intersectionOf/rdf:rest*/rdf:first))* ?superclass .
}
--------------
| superclass |
==============
| :A         |
| _:b0       |
| :B         |
| :C         |
| _:b1       |
--------------

Now, the blank nodes there are the anonymous intersection class and the anonymous restriction class. If you don't want to include them in the results, you can filter them out pretty easily:

prefix :      <https://stackoverflow.com/q/21092246/1281433/data.owl#> 
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 ?superclass where {
  :A (rdfs:subClassOf|(owl:intersectionOf/rdf:rest*/rdf:first))* ?superclass .
  filter(!isBlank(?superclass))
}
--------------
| superclass |
==============
| :A         |
| :B         |
| :C         |
--------------

You can add ^owl:equivalentClass|owl:equivalentClass into that property path as well, if you want to follow equivalent classes, too.

Doing this in Protégé

As I said, the results above were using Jena's command line tools. You said you wanted to do this in Protégé, and that makes things a bit harder, because it seems to introduce some problems. The last query I showed only produces A and B in Protégé; it doesn't include C for some reason:

enter image description here

However, the treatment of blank nodes is a bit better (i.e., we can remove the filter and get some useful output):

enter image description here

I'm not sure how to get the same output that Jena gives in Protégé, unfortunately, but I'm emailing their mailing list about it.

Community
  • 1
  • 1
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • sorry sir. but not work for me. please try this rdf file http://www.sendspace.com/file/5olz6h and use protege to sparql query this http://protege.stanford.edu/download/registered.html – user3190242 Jan 13 '14 at 14:11
  • 2
    @user3190242 That's a 45 MB rdf file. I'm not going to be able to download and test with that I'm afraid. Please note that questions on StackOverflow, as much as possible, need to be reproducible. Please create a smaller ontology that you can copy and paste into the question, and tell us what sort of results you're expecting. Without some data to work with, and without knowing what results you're trying to get, we can't do much better than this. – Joshua Taylor Jan 13 '14 at 16:19
  • This all work on Protege to test, but not on DotNetRdf it can't not get any output they was Exception "The value of a variable in a Set cannot be changed" this error occur by around rdf:rest*/rdf:first because i try to remove some * then no error and no data – user3190242 Jan 14 '14 at 09:11
  • 1
    @user3190242 You didn't mention using dotNetRDF in your question; you mentioned Progtégé. If this works for you in Protégé, then you might want to accept the answer. The dotNetRDF specific question would be better asked as another question where you'll be able to provide more information (and more people will see it, including dotNetRDF developers, whereas many people won't see these comments). – Joshua Taylor Jan 14 '14 at 17:35