I have loaded the pizza ontology into Stardog and Blazegraph, along with some triples I authored, including a pizza with four toppings. I have tried to make the toppings distinct, as @AKSW suggested.
The pizza ontology defines an interesting pizza as a pizza with at least three toppings. I'm pretty sure I have OWL reasoning enabled, but neither triplestore says that my pizza is interesting.
Can anybody show me settings that enable this inference in any freely available triplestore or point out what I've done wrong with my triples? Especially, should I be able to infer that pizza instances, pizza classes, or both are "interesting"?
Interesting pizza definition:
pizza:InterestingPizza rdf:type owl:Class ;
owl:equivalentClass [ owl:intersectionOf ( pizza:Pizza
[ rdf:type owl:Restriction ;
owl:onProperty pizza:hasTopping ;
owl:minCardinality "3"^^xsd:nonNegativeInteger
]
) ;
rdf:type owl:Class
] ;
rdfs:label "PizzaInteressante"@pt .
My additional triples:
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#> .
<http://www.co-ode.org/ontologies/pizza/pizza.owl#marksPizzaClass>
a owl:Class ;
owl:equivalentClass [
a owl:Restriction ;
owl:onProperty <http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping> ;
owl:someValuesFrom <http://www.co-ode.org/ontologies/pizza/pizza.owl#CaperTopping>
], [
a owl:Restriction ;
owl:onProperty <http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping> ;
owl:someValuesFrom <http://www.co-ode.org/ontologies/pizza/pizza.owl#JalapenoPepperTopping>
], [
a owl:Restriction ;
owl:onProperty <http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping> ;
owl:someValuesFrom <http://www.co-ode.org/ontologies/pizza/pizza.owl#LeekTopping>
], [
a owl:Restriction ;
owl:onProperty <http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping> ;
owl:someValuesFrom <http://www.co-ode.org/ontologies/pizza/pizza.owl#MozzarellaTopping>
], [
a owl:Restriction ;
owl:onProperty <http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping> ;
owl:someValuesFrom <http://www.co-ode.org/ontologies/pizza/pizza.owl#PineKernels>
] ;
rdfs:subClassOf <http://www.co-ode.org/ontologies/pizza/pizza.owl#Pizza> ;
rdfs:label "mark's pizza class" .
<http://www.co-ode.org/ontologies/pizza/pizza.owl#marksPizzaClassMember>
a owl:NamedIndividual, <http://www.co-ode.org/ontologies/pizza/pizza.owl#marksPizzaClass> ;
rdfs:label "a member of the mark's pizza class" .
<http://www.co-ode.org/ontologies/pizza/pizza.owl#marksPizzaInstance>
a owl:NamedIndividual, <http://www.co-ode.org/ontologies/pizza/pizza.owl#Pizza> ;
pizza:hasTopping pizza:marksPeppers, pizza:topping1, pizza:topping2, pizza:topping3, pizza:topping4 ;
rdfs:label "mark's pizza instance" .
pizza:marksPeppers
a owl:NamedIndividual, pizza:JalapenoPepperTopping ;
rdfs:label "mark's special spicy jalapenos" .
pizza:topping1
a owl:NamedIndividual, pizza:MozzarellaTopping ;
rdfs:label "mark's semi secret topping one" .
pizza:topping2
a owl:NamedIndividual, pizza:PineKernels ;
rdfs:label "mark's semi secret topping two" .
pizza:topping3
a owl:NamedIndividual, pizza:CaperTopping ;
rdfs:label "mark's semi secret topping three" .
pizza:topping4
a owl:NamedIndividual, pizza:LeekTopping ;
rdfs:label "mark's semi secret topping four" .
[]
a owl:AllDifferent ;
owl:distinctMembers (
pizza:marksPeppers
pizza:topping1
pizza:topping2
pizza:topping3
pizza:topping4
) .
Query for any knowledge about a pizza instance with five distinct toppings:
prefix pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#>
select *
where
{ pizza:marksPizzaInstance ?p ?o }
Result from Stardog (I have manually replaced full URIs with prefixed URIs):
+---------------------+----------------------------+
| p | o |
+---------------------+----------------------------+
| pizza:hasIngredient | pizza:topping1 |
| pizza:hasIngredient | pizza:topping2 |
| pizza:hasIngredient | pizza:topping3 |
| pizza:hasIngredient | pizza:topping4 |
| pizza:hasIngredient | pizza:marksPeppers |
| pizza:hasTopping | pizza:topping1 |
| pizza:hasTopping | pizza:topping2 |
| pizza:hasTopping | pizza:topping3 |
| pizza:hasTopping | pizza:topping4 |
| pizza:hasTopping | pizza:marksPeppers |
| rdfs:label | mark's pizza instance |
| rdf:type | owl:Thing |
| rdf:type | pizza:DomainConcept |
| rdf:type | pizza:Food |
| rdf:type | pizza:Pizza |
| rdf:type | pizza:SpicyPizza |
| rdf:type | pizza:SpicyPizzaEquivalent |
| rdf:type | pizza:CheeseyPizza |
| rdf:type | pizza:marksPizzaClass |
+---------------------+----------------------------+
Stardog has inferred that my pizza has ingredients (because it has toppings), that my pizza is a food, and even that my pizza is spicy because it has Mark's jalapeno peppers as a topping. But it hasn't inferred membership in the interesting pizza class.
Here are my Stardog reasoning settings:
Reasoning type: SL
Reasoning approximate: ON
SameAs reasoning: FULL
TBox named graph: *
I played a bit with Stardog 5.0 and got some more insights:
From an OWL DL view, the ontology is expressive enough to infer that
pizza:marksPizzaInstance rdf:type pizza:InterestingPizza .
This can be evaluated with Protege for example. A sample explanation that can be computed with the pretty cool Protege feature would be:
I could achieve the same in Stardog by enabling DL
reasoning:
bin/stardog-admin db offline pizzaDB
bin/stardog-admin metadata set -o reasoning.type=DL pizzaDB
bin/stardog-admin db online pizzaDB
Result:
+-------------------+-------------------------+
| p | o |
+-------------------+-------------------------+
| pizza:hasTopping | pizza:topping1 |
| pizza:hasTopping | pizza:topping2 |
| pizza:hasTopping | pizza:marksPeppers |
| pizza:hasTopping | pizza:topping3 |
| pizza:hasTopping | pizza:topping4 |
| rdf:type | pizza:Pizza |
| rdf:type | owl:Thing |
| rdf:type | pizza:InterestingPizza |
+-------------------+-------------------------+
For the Stardog profile SL
it doesn't work because the axiom is not in the profile. This can be recognized when looking into the Stardog log file which reports all ignored axioms:
WARN 2017-07-03 09:54:51,219 [XNIO-1 task-6] com.clarkparsia.blackout.ProfileFilterBase:apply(39):
Not a valid SL axiom:
EquivalentClasses(pizza:InterestingPizza, and(pizza:Pizza, min(pizza:hasTopping,3,owl:Thing)))
What I tried then is to add an SWRL rule since it's supported by the SL
profile:
Pizza(?x), hasTopping(?x, ?y1), hasTopping(?x, ?y2), hasTopping(?x, ?y3),
DifferentFrom (?y1, ?y2), DifferentFrom (?y1, ?y3), DifferentFrom (?y2, ?y3)
-> InterestingPizza(?x)
Surprisingly, this did not work either. I guess I missed some important thing and I'm still investigating why this doesn't work.
Lastly, I tried a Stardog rule instead of SWRL which has a pretty neat syntax close to SPARQL (BGPs are basically used):
[] a rule:SPARQLRule ;
rule:content """
PREFIX :<http://www.co-ode.org/ontologies/pizza/pizza.owl#>
IF {
?p a :Pizza ;
:hasTopping ?t1 , ?t2, ?t3
FILTER(?t1 != ?t2 && ?t1 != ?t3 && ?t2 != ?t3)
}
THEN {
?p a :InterestingPizza
}""" .
This works as expected and the SPARQL query returns the desired inferred triple.