SPIN Modeling Vocabulary

Version 1.0.1, July 24, 2009

Authors:
Holger Knublauch <holger@topquadrant.com>

Abstract

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.

Status of This Document

Version 1.0.1

Previous version: Version 1.0.0 (December 31, 2008)

This document is part of the SPARQL Inferencing Notation (SPIN) specification.


Table of Contents

1 Introduction

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.

 

2 Class Description Vocabulary

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.

2.1 Constraints

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:

	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.

2.2 Rules

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.

2.3 Constructors

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.

 

3 Meta-Modeling Vocabulary

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.

3.1 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

3.2 Functions

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

 

4 SPIN Libraries

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.

4.1 SPIN and the Semantic Web

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.

4.2 SPIN Imports

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
              ] ;...

 

Appendix: Reference

The URL of the SPIN schema is http://spinrdf.org/spin