Thursday, January 08, 2009

Understanding SPIN Functions

We have recently introduced SPIN, a light-weight vocabulary that enables the use of SPARQL to define constraints and inference rules for semantic web models. One very powerful facet of SPIN is that it can be used to define new SPARQL FILTER and LET functions without writing a single line of programming code. The goal of this blog entry is to explain the mechanisms of user-defined SPIN functions using an example from the kennedysSPIN ontology that is shipped with TopBraid Composer 3.0.

Let's look at an example function called getFather that returns the father of a given person:


Each SPIN function is an instance of the metaclass spin:Function. The best way to create a new function is to create a subclass of spin:Functions, a system class that groups together all available functions in the class hierarchy. The name of the function defines the URI under which is will be accessible from SPARQL queries. The function getFather is in a file with the default namespace, i.e. no prefix is needed to call it. The following example shows a function call of :getFather() in the LET assignment.


You can see that the getFather function takes one argument. Each SPIN function must formally declare its arguments. For each argument, the function class must have a spin:constraint that points to an spl:Argument object. For each argument of the function, the spl:Argument specifies:
  • a comment describing the argument
  • the name and index (e.g., sp:arg1 for the first argument)
  • the value type (such as xsd:string)
  • whether it is optional or not
  • a default value in case it is optional
The easiest way of creating such an Argument definition in TopBraid is via drag and drop: locate sp:arg1 in the Properties View and then drag it over the spin:constraint label to instantiate a spl:Argument template. Here is the definition of the first (and only) argument of getFather in TopBraid:


The fact that those arguments are attached using spin:constraint might be confusing at first. You can ignore this and simply treat it as a convention that SPIN uses to look up which arguments are defined for a function. A technical explanation is that function calls are instances of the function class, and that those instances must fulfill the value type constraint encoded in the spl:Argument. spl:Argument is a SPIN template that encodes this value type check by means of another SPARQL query. But again, you can ignore this aspect.

But now let's have a look at the key aspect of a SPIN function definition: the function's body. The property spin:body links a function class with a SPARQL query. This is the query that will be executed whenever the function is called. The SPARQL query must be either an ASK query or a SELECT query.
  • If the body is an ASK query, then the function's result is true or false
  • If the body is a SELECT query, then the function's result is the first variable binding of the result variable in the SELECT clause. All other values will be ignored. Null will be returned if no binding exists.
In the getFather function, the body is a SELECT function, because we are interested in a specific instance of person, bound to the result variable ?father:


As you can see in the screenshot above, the body query refers to the variable ?arg1 and TopBraid Composer displays those variables in bold face. At execution time, ?arg1 will already have a value pre-assigned to it, namely the function's argument. In the following function call, ?arg1 is bound to the instance kennedys:JohnKennedy.


Now, when the SPIN engine executes the getFather function, it will pre-bind the ?arg1 argument so that it becomes:


So to summarize, SPIN functions are wrapped SPARQL queries that contain references to argument variables such as ?arg1 and ?arg2. These argument variables will be pre-assigned to the actual arguments at execution time.

Once you have defined your function, you can store them in a file ending with .spin., e.g. myFunctions.spin.n3 and you will be able to use them anywhere in TopBraid without even importing the function's file. This allows anyone to create and share libraries of functions, for example to do generic things such as unit conversion.

These very same mechanisms are also used to define SPIN templates, but this is another topic...

0 Comments:

Post a Comment

<< Home