Introduction
Before we begin the tutorial there are few things to keep in mind.
The reasoner supports a subset of the full RDFS and OWL constructs (see below).
The tutorial examples below are in Lisp. You can find examples of using the reasoner in the other tutorials as well. See the Quick Start if you need more information on getting started.
This tutorial is written for people who know how to get around in the IDE or in Emacs. You can load this file in a buffer and start executing its forms from top to bottom.
The Lisp program 'reasoner-tutorial.cl' contains all of the illustrative examples below. You may want to open this in your Lisp development environment and follow along by evaluating its forms as you go. The program is in the 'tutorial-files' sub-directory of the AllegroGraph installation directory.
Reasoning Supported.
We support the following RDFS and OWL predicates:
- rdf:type
- rdfs:domain
- rdfs:range
- rdfs:subClassOf
- rdfs:subPropertyOf
- owl:inverseOf
- owl:sameAs
- owl:TransitiveProperty
We also support owl:hasValue
, owl:someValuesFrom
and owl:allValuesFrom
reasoning. Its use is covered in a separate tutorial.
Note that the reasoner is designed to efficiently answer questions like "What are properties of this subject?" or "Tell me all the subjects that have this type?" It is not designed for efficiently determining all of the inferred triples in a store (e.g., "Tell me everything you know?"). You should expect fast answers for queries whose predicate is specified but you will not see good performance for more open-ended calls to get-triples
. We will continue to enhance the reasoner as AllegroGraph develops.
Before you look up the semantics of these predicates in the W3C documentation you may want to first examine the examples in the tutorial below. Note that for efficiency's sake, our RDFS++ reasoner will not make every possible inference given a triple-store's ground triples. 1 We are constantly improving our inference algorithms and will continue to extend the reasoner's reach. If there are particular inferences that are important to you and AllegroGraph is not making them, please let us know so that we can work together to reach a solution.
Using the reasoner in AllegroGraph
You use the RDFS++ reasoner by calling apply-rdfs++-reasoner on a regular triple-store. For example, suppose we create a triple-store and add two triples (if you not familiar with the !-notation, see the section of the reference-guide on future-parts):
;; make sure the !-reader is on
> (enable-!-reader)
> (enable-print-decoded t)
t
> (register-namespace "ex" "http://franz.com/simple#")
"http://franz.com/simple#"
> (defparameter ground-ts (create-triple-store "sample"))
#<triple-db /home/agraph/sample, open @ #x13d41812>
> (add-triple !ex:jans !ex:owns !ex:birra)
1
> (add-triple !ex:jans !owl:sameAs !ex:jannes)
2
We'll make sure that the triples are in there and use enable-print-decoded so that the rest of this example is easier to read:
> (print-triples *db* :format :concise)
<1: ex:jans ex:owns ex:birrabirra>
<2: ex:jans owl:sameAs ex:jannesjannes>
; No value
If we ask for all of the triples whose predicate is !ex:owns
, we get back the single ground triple.
> (get-triples-list :p !ex:owns)
(<jans owns birra>)
nil
If we want to use AllegroGraph's RDFS++ reasoner, we call apply-rdfs++-reasoner
. If called with no additional parameters, this will encapsulate the current triple-store (i.e., *db*) with a reasoning-triple-store whose reasoner is of type rdfs++-reasoner. It will also set *db* to this new store. The return value of the call makes it clear what has happened.
> (defparameter inferred-ts (apply-rdfs++-reasoner))
#<reasoning-triple-store
sample, inner #<triple-db /home/agraph/sample, open @ #x13d41812>
@ #x140a26f2>
Now if we make the same call to get-triples-list
, we get two results back. One ground triple and one that has been inferred.
> (get-triples-list :p !ex:owns)
(<jans owns birra>
<jannes owns birra>)
Note that we can specify which triple-store to query using the :db
argument. If we ask for the triples from ground-ts
, that is what we will get. We can also accomplish the same thing by using the reasoning-triple-store's ground-triple-store:
> (get-triples-list :p !ex:owns :db ground-ts)
(<jans owns birra>)
> (get-triples-list :p !ex:owns :db (ground-triple-store *db*))
(<jans owns birra>)
Functions discussed in this tutorial.
This tutorial discusses: apply-rdfs++-reasoner
, ground-triple-store
and get-triples-list
.
As discussed above, apply-rdfs++-reasoner
wraps a triple-store in a reasoning-triple-store and uses the rdfs++-reasoner as the reasoning class.
Returns a new reasoning-triple-store which wraps db
with an rdfs++-reasoner.
db
- the triple-store to encapsulate. The defaults to the value of *db*. Ifdb
is *db* then *db* will be set to the returned reasoning-triple-store.name
- the name to give the encapsulated-triple-store. Defaults to the current db-name of thedb
prefixed with rdfs++- and with a generated suffix .restriction-reasoning-enabled
- when true, enable OWL hasValue reasoning. The default is nil.inferred-graph
- This argument specifies the graph component of all inferred triples. The default is to use the default graph of the specified triple store.cached-wrapper-key
- If this argument isnil
, the call creates a new instance of a reasoning wrapper; this instance will cause a new invocation of prepare-reasoning when the first query is issued. If the argument is not nil, it is used as a key in an equalp hash-table; if a previously created wrapper is found, the previous instance is used. If no entry is found, a new wrapper is created and saved in the table. The default value is taken from the variable*cached-wrapper-key*
. The initial value of this variable is nil.remote-reasoning
- This argument is meaningful only when the db argument is a remote-triple-store instance. A non-nil value specifies that the reasoning wrapper is created on the server side. The value returned byapply-rdfs++-reasoner
is a newremote-triple-store
instance pointing to the reasoner on the server side.
You can query a reasoning-triple-store almost anywhere that you can use a regular triple-store. SPARQL, our family of Prolog select functors, get-triples and get-triples-list all know how to work with a reasoning-triple-store.
It's helpful to be able to quickly print out the results of a query. For this purpose, we define a new function ptl
(for print-triples-list):
(defun ptl (s p o)
(print-triples (get-triples :s s :p p :o o) :format :concise))
As you can see, it simply passes the s-p-o
pattern to get-triples
and then uses print-triples
to display them in an easy to read form.
(ptl !ex:Jans !ex:has nil)
Note that there is a problem in the query optimizer's handling of uncommitted triples and RDFS reasoning. In certain cases involving uncommitted triples, the optimizer will produce incorrect plans that may return fewer results than expected. The two possible work-arounds are to either call commit-triple-store before executing the query or to add the clause (:use-maps nil)
to the query plan. This problem will be corrected in the near future. See the reference guide for more details about the query planner.
Finally, the reasoner introduces a new Prolog functor q that is used like q- in prolog clauses. The difference is that q-
will work on the ground-triple-store whereas q
will work with the actual *db* (obviously, if *db* is a non-encapsulated-store, then q-
and q
will be the same.)
Example: Assume that *db* is a reasoning-triple-store, then using q-
...
(select (?x)
(q- ?x !cyc:isa !cyc:Terrorist))
will find all the triples that literally have the predicate !cyc:isa
and the object !cyc:Terrorist
.
This next query does the same thing but uses the reasoner and might return more triples.
(select (?x)
(q ?x !cyc:isa !cyc:Terrorist))
Getting Ready
The examples below assume that the following code has been evaluated in your Lisp session. So please make sure you do so in your session before continuing.
(require :agraph)
(in-package :triple-store-user)
(enable-!-reader)
(enable-print-decoded t)
(defun ptl (s p o)
;; short for print-triples-list
(print-triples (get-triples :s s :p p :o o) :format :concise))
(register-namespace
"ex" "http://franz.com/example#" :errorp nil)
Reasoner Examples
The examples below assume that you have using an RDFS++ triple-store using something like. Note that if ground-ts
is already open, then you will not be able to recreate it unless you close it first:
(defparameter ground-ts (create-triple-store "sample"))
(apply-rdfs++-reasoner)
Each example removes all of the triples in the store, adds some new triples, and makes some queries to illustrate the different sorts of reasoning that AllegroGraph supports.
Inverse of
(delete-triples)
(add-triple !ex:jans !ex:owns !ex:birra)
(add-triple !ex:owned-by !owl:inverseOf !ex:owns)
(add-triple !ex:has !owl:inverseOf !ex:owned-by)
(ptl !ex:birra !ex:owned-by nil)
(ptl nil !ex:owned-by nil)
(ptl nil !ex:owned-by !ex:jans)
(ptl !ex:jans !ex:has nil)
(ptl nil !ex:has nil)
(ptl nil !ex:has !ex:birra)
(ptl nil nil nil)
; this will return nothing
; because it works on only the triples explicitly
; added to the triple-store
(select (?x)
(q- !ex:birra !ex:owned-by ?x))
; this will return something
; because it works on inferred triples
(select (?x)
(q !ex:birra !ex:owned-by ?x))
Sub-property of
(delete-triples)
(add-triple !ex:jans !ex:has-pet !ex:birra)
(add-triple !ex:has-pet !rdfs:subPropertyOf !ex:owns)
(add-triple !ex:birra !ex:friend-of !ex:samira)
(ptl !ex:jans !ex:owns !ex:birra)
(ptl !ex:jans !ex:owns nil)
(ptl nil !ex:owns !ex:birra)
(ptl !ex:jans !ex:has-pet !ex:birra)
(ptl !ex:jans !ex:has-pet nil)
(ptl nil !ex:has-pet !ex:birra)
(select (?x ?y)
(q !ex:jans !ex:owns ?x)
(q ?x !ex:friend-of ?y))
inverse and sub properties
(delete-triples)
(add-triple !ex:jans !ex:has-pet !ex:birra)
(add-triple !ex:owned-by !owl:inverseOf !ex:owns)
(add-triple !ex:has !owl:inverseOf !ex:owned-by)
(add-triple !ex:has-pet !rdfs:subPropertyOf !ex:owns)
(add-triple !ex:pet-of !owl:inverseOf !ex:has-pet)
;; direct triples
(ptl !ex:jans !ex:has-pet !ex:birra)
(ptl nil !ex:has-pet !ex:birra)
(ptl !ex:jans !ex:has-pet nil)
;; inverse of !ex:has-pet
(ptl !ex:birra !ex:pet-of !ex:jans)
(ptl nil !ex:pet-of !ex:jans)
(ptl !ex:birra !ex:pet-of nil)
;; subproperty
(ptl !ex:jans !ex:owns !ex:birra)
(ptl !ex:jans !ex:owns nil)
(ptl nil !ex:owns !ex:birra)
;; inverse of subproperty
(ptl !ex:birra !ex:owned-by !ex:jans)
(ptl nil !ex:owned-by !ex:jans)
(ptl !ex:birra !ex:owned-by nil)
;; inverse of inverse
(ptl !ex:jans !ex:has !ex:birra)
(ptl nil !ex:has !ex:birra)
(ptl !ex:jans !ex:has nil)
Same-as
(create-triple-store "rdfs-tutorial")
(add-triple !ex:jans !ex:owns !ex:birra)
(add-triple !ex:jans !owl:sameAs !ex:jannes)
(add-triple !ex:aasman !owl:sameAs !ex:jannes)
(add-triple !ex:birra !owl:sameAs !ex:son-of-samira)
(ptl !ex:aasman !ex:owns !ex:son-of-samira)
(ptl !ex:aasman !ex:owns nil)
(ptl nil !ex:owns !ex:son-of-samira)
(ptl nil !ex:owns nil)
Same-as, inverse, and sub-properties
(create-triple-store "rdfs-tutorial")
(add-triple !ex:jans !ex:has-pet !ex:birra)
(add-triple !ex:owned-by !owl:inverseOf !ex:owns)
(add-triple !ex:has !owl:inverseOf !ex:owned-by)
(add-triple !ex:has-pet !rdfs:subPropertyOf !ex:owns)
(add-triple !ex:pet-of !owl:inverseOf !ex:has-pet)
(add-triple !ex:birra !ex:age !ex:twelve)
(add-triple !ex:jans !owl:sameAs !ex:jannes)
(add-triple !ex:aasman !owl:sameAs !ex:jannes)
(add-triple !ex:birra !owl:sameAs !ex:son-of-samira)
;; direct triples
(ptl !ex:aasman !ex:has-pet !ex:son-of-samira)
(ptl nil !ex:has-pet !ex:son-of-samira)
(ptl !ex:aasman !ex:has-pet nil)
;; inverse of !ex:owns
(ptl !ex:son-of-samira !ex:pet-of !ex:aasman)
(ptl nil !ex:pet-of !ex:aasman)
(ptl !ex:son-of-samira !ex:pet-of nil)
;; inverse of inverse
(ptl !ex:aasman !ex:has !ex:son-of-samira)
(ptl nil !ex:has !ex:son-of-samira)
(ptl !ex:aasman !ex:has nil)
;; subproperty
(ptl !ex:aasman !ex:owns !ex:son-of-samira)
(ptl !ex:aasman !ex:owns nil)
(ptl nil !ex:owns !ex:son-of-samira)
;; inverse of subproperty
(ptl !ex:son-of-samira !ex:owned-by !ex:aasman)
(ptl nil !ex:owned-by !ex:aasman)
(ptl !ex:son-of-samira !ex:owned-by nil)
;; what to do with this?
(ptl nil nil nil)
;; but what if predicate is unknown?
(ptl !ex:jans nil !ex:birra) ;; this returns only one valid result
;; what should i do here, find all the
;; predicates defined for !ex:aasman (and the sames)
;; and then try them all?
(ptl !ex:aasman nil !ex:birra)
(ptl !ex:aasman nil nil)
type with sub-class
(delete-triples)
(add-triple !ex:mammal !rdfs:subClassOf !ex:animal)
(add-triple !ex:human !rdfs:subClassOf !ex:mammal)
(add-triple !ex:man !rdfs:subClassOf !ex:human)
(add-triple !ex:jans !rdf:type !ex:man)
(add-triple !ex:jans !owl:sameAs !ex:jannes)
(add-triple !ex:aasman !owl:sameAs !ex:jannes)
(ptl !ex:jans !rdf:type !ex:man)
(ptl !ex:jans !rdf:type !ex:human)
(ptl !ex:jans !rdf:type nil)
(ptl !ex:aasman !rdf:type !ex:man)
(ptl !ex:aasman !rdf:type !ex:human)
(ptl !ex:aasman !rdf:type nil)
(ptl nil !rdf:type !ex:man)
(ptl nil !rdf:type !ex:human)
(ptl nil !rdf:type nil)
type with range
(delete-triples)
(add-triple !ex:jans !ex:has-pet !ex:birra)
(add-triple !ex:has-pet !rdfs:range !ex:pet)
(add-triple !ex:pet !rdfs:subClassOf !ex:mammal)
(add-triple !ex:fatcat !owl:sameAs !ex:birra)
(ptl !ex:birra !rdf:type !ex:pet)
(ptl !ex:birra !rdf:type nil)
(ptl nil !rdf:type !ex:pet)
(ptl !ex:birra !rdf:type !ex:mammal)
(ptl !ex:fatcat !rdf:type !ex:mammal)
type with domain
(delete-triples)
(add-triple !ex:jans !ex:has-pet !ex:birra)
(add-triple !ex:has-pet !rdfs:domain !ex:human)
(add-triple !ex:human !rdfs:subClassOf !ex:mammal)
(add-triple !ex:jans !owl:sameAs !ex:aasman)
(ptl !ex:jans !rdf:type !ex:human)
(ptl !ex:jans !rdf:type nil)
(ptl nil !rdf:type !ex:human)
;; not returning all solutions..
(ptl nil !rdf:type nil)
Transitivity with Same As
(delete-triples)
(add-triple !ex:contains !rdf:type !owl:TransitiveProperty)
(add-triple !ex:usa !ex:contains !ex:california)
(add-triple !ex:golden-state !ex:contains !ex:contra-costa)
(add-triple !ex:contra-costa !ex:contains !ex:moraga)
(add-triple !ex:usa !owl:sameAs !ex:uncle-sam)
(add-triple !ex:moraga !owl:sameAs !ex:mytown)
(add-triple !ex:california !owl:sameAs !ex:golden-state)
(ptl !ex:usa !ex:contains !ex:moraga)
(ptl !ex:uncle-sam !ex:contains !ex:mytown)
(ptl !ex:golden-state !ex:contains !ex:moraga)
(ptl !ex:california !ex:contains !ex:moraga)
(ptl !ex:california !ex:contains !ex:mytown)
(ptl !ex:usa !ex:contains nil)
(ptl !ex:uncle-sam !ex:contains nil)
(ptl nil !ex:contains !ex:moraga)
(ptl nil !ex:contains !ex:mytown)
Footnotes
- In particular, some non-rdf:type and rdfs:subClassOf reasoning involving chains of transitive predicates will not be followed unless the predicate is supplied as part of the query. ↩