The SPIN Modeling Vocabulary is a light-weight collection of
RDF properties and classes to support the use of SPARQL to
specify rules and logical constraints. Based on an RDF
representation of SPARQL queries, SPIN defines three class
description properties:
spin:constraint
can be used to define conditions
that all members of a class must fulfill.
spin:rule
can be used to specify inference rules
using SPARQL CONSTRUCTs.
spin:constructor
can be used to initialize new
instances with default values.
In addition to these class description properties, SPIN provides
a powerful meta-modeling capability that can be used to build
your own modeling language and SPARQL extensions.
These meta-modeling features provide the ability to encapsulate
reusable SPARQL queries into templates, and to derive
new SPARQL functions from other SPARQL queries and functions.
Version 1.0.1
Previous version: Version 1.0.0 (December 31, 2008)
This document is part of the SPARQL Inferencing Notation (SPIN) specification.
SPARQL is now firmly established as the standard query language for
RDF models and Semantic Web data. Many RDF APIs and databases come
with SPARQL support out-of-the-box. At the same time, SPARQL can be
regarded as more than just a query language with a SELECT
keyword: SPARQL also provides means to check whether certain conditions
currently hold in an RDF model (ASK
), and to derive new
triples from existing triples (CONSTRUCT
).
While these powerful elements are increasingly used by developers to
solve application and modeling problems, SPIN defines a systematic
framework on how to use SPARQL queries to drive applications.
SPIN takes SPARQL a step further and uses it to enhance existing RDF
models with formal, executable descriptions.
Based on the SPIN SPARQL Syntax, the SPIN Modeling Vocabulary (described in this document) defines a light- weight set of RDFS classes and properties that can be used to systematically embed SPARQL queries into RDF models so that they can be executed with well-defined semantics. The basic idea is to use specific RDF properties to link classes with SPARQL queries so that those SPARQL queries can be executed with a given context.
The following chapters describe how this approach can be used to describe classes (and their instances, Chapter 2), and how to build more complex modeling constructs out of reusable SPARQL queries (Chapter 3). Chapter 4 describes guidelines on how the SPIN vocabulary should be used in the context of the Semantic Web.
The SPIN class description vocabulary defines several RDF properties
that can be used to attach SPARQL queries to classes. The property
spin:query
is the common base property of
spin:constraint
, spin:rule
and
spin:constructor
. SPIN-compliant tools can use these
properties to execute SPARQL queries over the instances of the associated
class(es) in response to events. For example, spin:rule
can be used by SPIN reasoning engines to construct inferred RDF triples
from the currently asserted information in the model.
The SPARQL queries referenced by the SPIN properties are interpreted
in the context of the associated class. At run-time, the SPARQL variable
?this
is pre-bound with instances of the class and its
sub-classes. Typically, the query itself does not need to bind
?this
to any value in the WHERE
clause.
The execution context (e.g., inference engine) will do this before the
query is executed.
SPIN takes an object-oriented world view on Semantic Web models,
in which SPARQL queries play a similar role like functions/methods.
Inheritance (expressed using rdfs:subClassOf
) is treated
in the sense that any query defined for superclasses will also be
applied to subclasses. In other words, SPIN class descriptors can
only "narrow down" and further restrict what has been defined further
up in the class hierarchy. In this spirit, global class
descriptions are those that are attached to the root class
rdfs:Resource
or its OWL equivalent owl:Thing
.
Those global queries may not even mention ?this
at all.
The following sections provide details on the three SPIN class description properties.
The property spin:constraint
can be used to link
rdfs:Classes
with SPARQL ASK
or
CONSTRUCT
queries.
Each ASK query defines a constraint that is assumed to evaluate to
false
for each instance of the associated class (and
its subclasses). In other words, if an ASK constraint evaluates to
true for one instance, then the instance violates the condition.
Optionally, CONSTRUCT queries can create instances of a
spin:ConstraintViolation
class that provide details
on a specific violation.
At query execution time, the SPARQL variable ?this
is bound
to the current instance of the class.
The following example defines a constraint on the class
ex:Parent
so that each instance of parent must have
at least one value for the ex:child
property.
ex:Parent a rdfs:Class ; rdfs:label "Parent"^^xsd:string ; rdfs:subClassOf ex:Person ; spin:constraint [ a sp:Ask ; rdfs:comment "must be at least 18 years old"^^xsd:string ; sp:where ([ sp:object sp:_age ; sp:predicate ex:age ; sp:subject spin:_this ] [ a sp:Filter ; sp:expression [ a sp:lt ; sp:arg1 sp:_age ; sp:arg2 18 ] ]) ].
In textual SPARQL syntax, the above query would read as:
# must be at least 18 years old ASK WHERE { ?this ex:age ?age . FILTER (?age < 18) . }
The following example uses a SPARQL CONSTRUCT query, which is
more complex than the ASK style but much more flexible.
The CONSTRUCT is assumed to create instances of the system class
spin:ConstraintViolation
. These instances are usually
blank nodes, and additional properties can be attached to
violation instances so that editing tools can guide user input:
rdfs:label
can provide a human-readable text
that explains the reason of the constraint violation
spin:violationRoot
can link to the resource
that is the source of the constraint violation
spin:violationPath
can point to a
path expression, which
is often the URI of a property
spin:constraint [ a sp:Construct ; sp:templates ([ sp:object spin:ConstraintViolation ; sp:predicate rdf:type ; sp:subject _:b1 ] [ sp:object spin:_this ; sp:predicate spin:violationRoot ; sp:subject _:b1 ] [ sp:object kennedys:spouse ; sp:predicate spin:violationPath ; sp:subject _:b1 ] [ sp:object "Same-sex marriage not permitted (in this model)" ; sp:predicate rdfs:label ; sp:subject _:b1 ]) ; sp:where ([ sp:object sp:_spouse ; sp:predicate kennedys:spouse ; sp:subject spin:_this ] [ sp:object sp:_gender ; sp:predicate kennedys:gender ; sp:subject spin:_this ] [ sp:object sp:_spouseGender ; sp:predicate kennedys:gender ; sp:subject sp:_spouse ] [ a sp:Filter ; sp:expression [ a sp:eq ; sp:arg1 sp:_gender ; sp:arg2 sp:_spouseGender ] ]) ]
In textual SPARQL syntax, the above query would read as:
CONSTRUCT { _:b0 a spin:ConstraintViolation ; spin:violationRoot ?this ; spin:violationPath kennedys:spouse ; rdfs:label "Same-sex marriage not permitted (in this model)" } WHERE { ?this kennedys:spouse ?spouse . ?this kennedys:gender ?gender . ?spouse kennedys:gender ?spouseGender . FILTER (?gender = ?spouseGender) . }
SPIN constraints can be used for various purposes, but in
particular to verify that an instance of a class maintains its
expected state with regards to its property values and
relationships with other resources. Simple SPIN constraints
may only verify the range of datatype literals, but others
may walk adjacent nodes as well. Anything that can be expressed
in SPARQL can be used in SPIN constraints, including queries
against other SPARQL end points, FILTER
clauses
and complex mathematical calculations.
Interactive tools such as editing forms may use the constraints to validate user input. Web services may check parameter ranges. Since SPIN queries are directly attached to class definitions in a machine-readable format, the intended "meaning" and scope of those classes can be clearly communicated to other agents.
Please note that the values of the spin:constraint
property may also be SPIN template calls,
assuming these templates wrap SELECT or ASK queries. Basically, SPIN
allows you to use templates whenever a query is expected, as long as
the query type matches the expectations.
The property spin:rule
can be used to link
rdfs:Classes
with SPARQL CONSTRUCT
queries.
Each Construct query defines an inference rule that is applied
to all instances of the associated class, and its subclasses.
For each binding of the pattern in the WHERE
clause of the rule the triple templates from the CONSTRUCT
clause are instantiated and added as inferred triples to the
underlying model. At query execution time, the SPARQL variable
?this
is bound to the current instance of the class.
The following example defines a rule that infers the values of the
ex:grandParent
property from values of ex:child
.
ex:Person a rdfs:Class ; rdfs:label "Person"^^xsd:string ; rdfs:subClassOf owl:Thing ; spin:rule [ a sp:Construct ; sp:templates ([ sp:object sp:_grandParent ; sp:predicate ex:grandParent ; sp:subject spin:_this ]) ; sp:where ([ sp:object spin:_this ; sp:predicate ex:child ; sp:subject sp:_parent ] [ sp:object sp:_parent ; sp:predicate ex:child ; sp:subject sp:_grandParent ]) ] .
In textual SPARQL syntax, the above query would read as:
CONSTRUCT { ?this ex:grandParent ?grandParent . } WHERE { ?parent ex:child ?this . ?grandParent ex:child ?parent . }
The property spin:ruleIndex
can be used to instruct the
SPIN rule engine about the order in which it should execute rules.
Rules will be executed in no specific order by default. However, the
rules at a given class (attached using spin:rule
) will
be executed in the order specified by the rule index. Rules that do
not have an index will be ordered next, alphabetically by their
rdfs:comment
. This allows developers to insert comments
such as "# Step 1: ...", "# Step 2: ..." etc as first lines of their
rules.
In some cases, rules may be imported from a library. Such library
files may only declare the rules themselves but have no additional
triples in them that would be relevant for the rule execution. The
base URI (owl:Ontology
) of such files can be annotated
to be an instance of spin:LibraryOntology
. In this
case, all triples from that named graph should be ignored by SPIN
rule engines.
The property spin:constructor
can be used to link
rdfs:Classes
with SPARQL CONSTRUCT
queries.
Each Construct query defines an inference rule that can be
applied to all new instances of the associated class and its
subclasses at creation-time. Constructors are usually only
evaluated once, to set initial default values to some properties
of the instances. At query execution time, the SPARQL variable
?this
is bound to the current instance of the class.
For example, if a user creates a new instance of
ex:USCitizen
then its constructor can be used to
automatically set its ex:birthCountry
property to ex:USA
. However, this value may of
course be replaced later, during the evolution of the model.
ex:USCitizen a rdfs:Class ; rdfs:label "US citizen"^^xsd:string ; rdfs:subClassOf ex:Person ; spin:constructor [ a sp:Construct ; sp:templates ([ sp:object ex:USA ; sp:predicate ex:birthCountry ; sp:subject spin:_this ]) ; sp:where () ] .
In textual SPARQL syntax, the above query would read as:
CONSTRUCT { ?this ex:birthCountry ex:USA . } WHERE { }
At execution time, the only triple that will be reliably present
for ?this
is the rdf:type
triple that
links ?this
with the class that has the constructor
attached to it, or a subclass thereof.
SPIN-compliant engines need to make sure that superclass
constructors are executed before subclass constructors.
As a consequence, constructors of subclasses may assume that
additional triples are present, and may query them in their
WHERE
clauses.
Constructors should also be executed by SPIN inference engines:
If a rule infers a new rdf:type
triple, then the
corresponding constructors should be called on the subject of the
type triple. The constructors should be executed after the rule
has been executed completely - this will make sure that all
triples mentioned in the rule's construct template will have been
created and can be queried by the WHERE clause of the constructors.
SPARQL queries are often similar and only differ in a value or two. SPIN can be used to generalize SPARQL queries so that they can be reused in multiple contexts. The SPIN Meta-Modeling Vocabulary described in the following sections introduces two mechanisms of encapsulating SPARQL query templates.
Templates are reusable "boxed" SPARQL queries that can be used in conjunction with
properties such as spin:rule
or spin:constraint
, but
also in other places.
The following example defines a template ex:MinCardinality
that can be used to verify that ?this
has at least
?count
values for a given property ?predicate
.
Note that the function ex:cardinality
is a user-defined
SPIN function that will be described later.
ex:MinCardinality a spin:Template ; rdfs:subClassOf spin:Templates ; rdfs:comment "Checks whether ?this has at least ?count values for a given property ?predicate." ; rdfs:label "Min cardinality"^^xsd:string ; spin:constraint [ a spl:Argument ; rdfs:comment "the minimum number of values expected" ; spl:predicate ex:count ; spl:valueType xsd:integer ] ; spin:constraint [ a spl:Argument ; rdfs:comment "the property being restricted" ; spl:predicate ex:predicate ; spl:valueType rdf:Property ] ; spin:labelTemplate "at least {?count} values for {?predicate}"^^xsd:string ; spin:body [ a sp:Ask ; sp:where ([ a sp:Filter ; sp:expression [ sp:arg1 [ sp:arg1 sp:_predicate ; a ex:cardinality ] ; sp:arg2 sp:_count ; a sp:lt ] ]) ] .
The above body query in SPARQL syntax looks like:
ASK WHERE { FILTER (ex:cardinality(?predicate) < ?count) . }
Templates are instances of the metaclass spin:Template
.
In order to "call" a template, the user needs to instantiate the template class.
In the following example, the above template ex:MinCardinality
is used to constrain that all instances of the class ex:Parent
must have at least one value for the ex:child
property.
ex:Parent a owl:Class ; rdfs:label "Parent"^^xsd:string ; rdfs:subClassOf owl:Thing ; spin:constraint [ a ex:MinCardinality ; ex:count 1 ; ex:predicate ex:child ] .
Each argument of a template must be represented by one argument descriptor
(instance of the template spl:Argument
).
Each argument descriptor must point to an RDF property using
spl:predicate
. This property will hold the actual template
values when the template is instantiated.
The local name of that property is used as variable name for the argument.
For example, the property sp:arg1
represents the variable
?arg1
.
Arguments can also have a value type using spl:valueType
and
might be spl:optional
.
It is strongly recommended to define an rdfs:comment
for
each argument, to describe the role of the argument in the query.
The encapsulated query itself must be stored using spin:body
.
Depending on the type of template, spin:body
must be an instance
of sp:Ask
, sp:Construct
, sp:Describe
or sp:Select
.
At execution time, the query will already have the variables declared in the argument descriptors pre-assigned with the arguments in the template call.
Templates should define a value for spin:labelTemplate
with place-holders for the variable names between { and } so that
user interfaces can render the template calls in a human-readable way.
For example the template call above would be rendered as
at least 1 values for ex:child
Templates can be published on the Semantic Web and then imported by other models. SPIN agents could in principle dynamically resolve templates from the internet, similar to distributed Web Services. Such template libraries can specify domain-specific modeling languages (as alternatives to, or in addition to languages like OWL). Since templates are executable, these template-based modeling languages have well-defined formal semantics.
See also: Understanding SPIN Templates
SPIN can be used to define new SPARQL functions so that these
new function can be used in expressions such as FILTER
or LET
clauses.
Technically, SPIN Functions are very similar to SPIN Templates.
Functions are defined by a body and zero or more argument descriptors.
The body of a function must be an Ask query, or a Select query with
exactly one result variable.
The following example declares a function ex:cardinality
that gets the number of values of a given property at the current
subject (?this
), using a SPARQL COUNT
query.
ex:cardinality a spin:Function ; rdfs:subClassOf spin:Functions ; rdfs:comment "Gets the number of values of a given property at the current subject (?this)." ; rdfs:label "cardinality"^^xsd:string ; spin:constraint [ a spl:Argument ; rdfs:comment "The property to get the cardinality of." ; spl:predicate sp:arg1 ] ; spin:body [ a sp:Select ; sp:resultVariables ([ a sp:Count ; sp:expression sp:_object ]) ; sp:where ([ sp:object sp:_object ; sp:predicate spin:_arg1 ; sp:subject spin:_this ]) ] .
Once the function is defined, it can be used in SPARQL queries such as
FILTER (ex:cardinality(ex:child) > 0)
The expression above is represented in SPIN syntax as
[ a sp:Filter ; sp:expression [ sp:arg1 [ sp:arg1 :child ; a ex:cardinality ] ; sp:arg2 0 ; a sp:gt ] ]
Arguments are declared the same way like with Templates (see above).
The main difference is that a function's arguments must be ordered
so that the traditional textual SPARQL notation can correctly round-
trip them. By default, a Function's arguments are sorted alphabetically
by their local name.
Functions must use the system properties sp:arg1
,
sp:arg2
etc to declare the arguments in their expected order.
Functions do not need to have a spin:body
. In those cases,
the execution environment is assumed to provide different implementations
of them, e.g. as hard-coded Java functions.
See also: Understanding SPIN Functions
SPIN is a modeling language that has been designed with the Semantic Web in mind. This chapter describes how SPIN documents should be organized to make the best use of this infrastructure.
SPIN constraints, rules and constructors are associated with RDFS/OWL classes
using dedicated properties such as spin:constraint
. On the
Semantic Web this means that when an RDFS class is shared online, then users
of the class will also get the associated semantics in the same way as they
get labels, comments etc. So typically, class definitions and semantics are
stored in the same document.
With the SPIN meta-modeling vocabulary the situation is slightly different,
because SPIN functions and templates can also be used in other places.
However, SPIN functions and templates have a unique URI and therefore can be
uploaded to some Semantic Web site so that SPIN-aware agents can find an
executable description of the function or template by following its URI.
In practice that means that SPIN users planning to share their files should
make sure that the selected URIs are de-referencable. In practice this simply
means that if a software agent encounters a SPIN function in a SPARQL query,
and the function is not natively known to the engine, then the engine can
follow the link to the function to get all triples needed to understand how
to execute it, including spin:body
etc.
If SPIN files are not shared on the Semantic Web but only used locally, then
it is a good practice to help the environment find function and template
definitions. In a system such as TopBraid, we recommend a naming convention
to store such SPIN files with an ending such as .spin.n3
or
.spin.rdf
. This makes it easier for tools to recognize that the
file may contain SPIN functions and templates so that the tool can pre-load
the functions into memory in advance.
Some constraint or rule libraries are independent from a particular domain
ontology, and rather describe general patterns. For example, it is possible
to describe the semantics of a subset of OWL using SPIN constraints, and thus
re-use the OWL restrictions vocabulary to validate integrity constraints on
existing OWL models. Such libraries may contain spin:constraints
that are simply attached to owl:Thing
or another global root class.
In order to use such libraries in the context of OWL, one option is to define
an owl:imports
to link the domain ontology with the constraint
library. However, this means that OWL semantics would be applied to the library
itself, because OWL engines would merge in all the triples from the SPIN file
and treat them on the same level as the actual domain triples. Furthermore,
the additional triples might clutter up user interfaces.
SPIN 1.0.1 introduces the spin:imports
property, that can be used
to link the base URI of a domain ontology with a SPIN file, specified by the
base URI of the SPIN file. For a SPIN constraint checker (or rule engine),
the spin:imports
keyword has the same meaning as owl:imports
,
i.e. all triples from the imported file will be added to the current RDF graph.
However, the triples specified by spin:imports
will not be imported
in an OWL sense and therefore remain invisible to any OWL tool.
In the following example, the current domain ontology (spinOWLTest) imports a
SPIN constraint library that defines a subset of OWL for constraint checking,
so that SPIN engines will report a constraint violation whenever an instance
of :Person
does not have 1 :lastName
. Note that this
file does not import the SPIN namespace - it just declares a prefix for it.
@prefix : <http://tests.spin.topbraid.org/imports/spinOWLTest#> . @prefix owl: <https://www.w3.org/2002/07/owl#> . @prefix spin: <http://spinrdf.org/spin#> . @prefix rdf: <https://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <https://www.w3.org/2000/01/rdf-schema#> . @prefix xsd: <https://www.w3.org/2001/XMLSchema#> . <http://tests.spin.topbraid.org/imports/spinOWLTest> rdf:type owl:Ontology ; spin:imports <http://topbraid.org/spin/spinowl> . :Person rdf:type owl:Class ; rdfs:label "Person"^^xsd:string ; rdfs:subClassOf owl:Thing ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:cardinality "1"^^xsd:int ; owl:onProperty :lastName ] ;...
The URL of the SPIN schema is http://spinrdf.org/spin