0
votes

I'm developing an ontology to model the relations in a manufacturing system. I broke it down to a similar scheme with dishes:

ex:potatoes  rdf:type            owl:Class .
ex:fish  rdf:type                owl:Class .
ex:beef  rdf:type                owl:Class .

ex:rice  rdf:type                owl:Class ;
         owl:disjointWith        ex:potatoes .

ex:chicken  rdf:type             owl:Class ;
            owl:disjointWith     ex:fish .

ex:pork  rdf:type                owl:Class ;
         owl:disjointWith        ex:beef .

ex:dish1  rdf:type              owl:Class ;
          rdfs:subClassOf       ex:dishes ;
          owl:unionOf      ( ex:pork ex:potatoes ) .

ex:dish2  rdf:type           owl:Class ;
          rdfs:subClassOf    ex:dishes ;
          owl:unionOf      ( ex:rice ex:chicken ) .

ex:dish3  rdf:type           owl:Class ;
          rdfs:subClassOf    ex:dishes ;
          owl:unionOf      ( ex:fish ex:potatoes ) .

ex:dish4  rdf:type           owl:Class ;
          rdfs:subClassOf   ex:dishes ;
          owl:unionOf      ( ex:beef ex:rice ) .

So I have some disjunct classes and I want to query the model like this: If somebody says he wants rice and chicken, exclude every dish which contains the disjunct classes (here fish and potatoes). After some research I have it like this:

              "PREFIX ex:   <http://example.org/>"+
             "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"+
              "PREFIX owl: <http://www.w3.org/2002/07/owl#>"+
              "PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>"+
              "PREFIX  rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"+    
                "SELECT ?x "+
                        "WHERE {"+
                           "?x rdfs:subClassOf ex:dishes. "+
                           "FILTER (!isBlank(?x))"+
                           "FILTER NOT EXISTS { "+
                             "?x rdfs:subClassOf ?y ."+
                             "?y rdfs:subClassOf ex:dishes ."+
                             "FILTER (?x!=?y)"+
                           "}"+
                           "FILTER NOT EXISTS {"+
                         "?z rdfs:subClassOf ?x ." +
                         "?z owl:disjointWith ex:chicken . }" +
                         "FILTER NOT EXISTS {"+
                         "?z rdfs:subClassOf ?x ." +
                         "?z owl:disjointWith ex:rice . }" +
                        "}";

It works and I get the correct result:

------------
| x        |
============
| ex:dish4 |
| ex:dish2 |
------------

Is there a more efficient way to do this? Seems unnecessary complicated. And do have to add the whole block with "FILTER NOT EXISTS { ?z rdfs:subClassOf ?x . ?z owl:disjointWith ex:chicken . } every time? Any advice?

1
No one with any ideas? - advocatis
Your ontology is a bit strange. When you say ex:dish1 ... owl:unionOf (ex:pork ex:potatoes), you're saying that dish1 is the union of pork and potatoes. That means that if something is a pork, then it's a dish1, and that if something is a potatoes, then it's a dish1. That means that, for instance, if something is a potatoes, then it's a dish1, but by the same reasoning, a dish3. So, a boiled potato would be classified as a dish1 and a dish3. Is that really what you're trying to say? - Joshua Taylor
I use this ontology only to build up the relationships, there won't be any individuals in it. Ok the real case is the following: I have a production line with many machines, each machine can be in a condition (running, stopped etc.). To see in which condition a machine is, I can measure characteristics. If I measure 'potatoes' and 'pork' I know its condition x. If I measure only 'pork' it could be in condition x or in y, further analysis required. And some characteristics are disjunct. If I measure 'chicken' it's definitely not condition z. Hope it's understandable.Appreciate your help! - advocatis
Actually, I'm not sure that that clarified all that much for me. In the case that you describe, it sounds like you would have a Class "MachineCondition" with members "Running", "Stopped", etc., and you'd want some other classes "Machine", "StoppedMachine (subclassof Machine and (hasCondition value Stopped))" and you'd have some other axioms to help infer which subclass of Machine an individual machine belongs to. E.g., ((Machine and (hasTemperature some int[<= 50])) subClassOf StoppedMachine) to say that if a machine has a temperature below 50, then it is a StoppedMachine... - Joshua Taylor
...and from knowing that it's a StoppedMachine, you'd be able to infer that is hasCondition Stopped. - Joshua Taylor

1 Answers

2
votes

I've modified the data a bit to make some of the representations a bit more direct, and without the confusion about the OWL semantics. However, it's directly analogous to the representation you're using, so you should just be able to change the properties and have this work. First, here's the data. You've got some ingredients, and certain ingredients are incompatible with others. (Incompatible implies disjoint, but disjoint doesn't imply incompatible. After all, chicken and rice are clearly distinct things, and thus disjoint classes, but that doesn't mean that they're incompatible as ingredients.)

@prefix : <urn:ex:>

# Incompatibities

:rice     :incompatibleWith :potatoes .
:potatoes :incompatibleWith :rice .
:chicken  :incompatibleWith :fish .
:fish     :incompatibleWith :chicken .
:beef     :incompatibleWith :pork .
:pork     :incompatibleWith :beef .

# Ingredients
:dish1 a :Dish ; :ingredients (:pork :potatoes) .
:dish2 a :Dish ; :ingredients (:rice :chicken) .
:dish3 a :Dish ; :ingredients (:fish :potatoes) .
:dish4 a :Dish ; :ingredients (:beef :rice) .

Now, the query simply needs to ask for dishes, and then check that each ingredient in the dish is not incompatible with either chicken or rice.

prefix : <urn:ex:>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?dish where {
  ?dish a :Dish .
  filter not exists {
    ?dish :ingredients/rdf:rest*/rdf:first ?ingredient .
    ?ingredient :incompatibleWith ?incompatibleIngredient .
    filter (?incompatibleIngredient in (:rice, :chicken))
  }
}
----------
| dish   |
==========
| :dish4 |
| :dish2 |
----------

If you're really concerned about space, you can even combine the two lines

?dish :ingredients/rdf:rest*/rdf:first ?ingredient .
?ingredient :incompatibleWith ?incompatibleIngredient .

into

?dish :ingredients/rdf:rest*/rdf:first/:incompatibleWith ?incompatibleIngredient .

I think that's a little bit harder to read, because it's implicit that the value in the list (what you get to by following :ingredients/rdf:rest*/rdf:first) is an ingredient in the dish.