Tuesday, January 5, 2010

How to: write new SPARQL functions with SPIN

An updated version of this blog post is now available as a chapter in the TopBraid Application Development Quickstart Guide (pdf).

This is the first of a series of short pieces on how to use various features of the TopBraid Suite application development tool set. For example, we'll see how to create a SPARQLMotion script, how to create a user interface with TopBraid Ensemble, how to create a web service, how to convert triples to XML and run an XSLT stylesheet on them, and how to use data from spreadsheets, databases, public SPARQL endpoints, and more. These postings will focus mostly on application development, and assume that you already know the basics of TopBraid Composer itself, which you can learn from the "TopBraid Composer Getting Started Guide" (pdf). Each posting will be assigned to the How to category of this blog to make it easier for readers to use them as a set.

This first entry shows how you can define your own functions using the SPARQL Inferencing Notation, because it's such an important building block for many of the techniques that we'll learn about in future entries. This material is excerpted from the "Getting Started with SPIN" (pdf) document, which is available for you to download. The complete "Getting Started with SPIN" document also covers inferencing, constructors, constraints, and more.

Before we cover the definition of new functions, let's review the calling of functions in TopBraid, because there are so many useful ones available to you.

Calling built-in functions

The "TopBraid SPARQLMotion Functions Library" page of TopBraid Composer's online help lists over 70 functions available for you to call from your applications, including string functions, mathematical functions, logical functions, and ontology functions. Because TopBraid Composer uses the Jena SPARQL engine, it supports the LET keyword for assignment of variables, which gives you a way to experiment with built-in variables using a short, simple SPARQL query.

For example, to try the mathematical function smf:random() (a TopBraid Composer extension to the Jena function library), enter the following query in the SPARQL view's Query Editor tab:

LET (?x := smf:random()).

To execute it, either click the "Execute SPARQL" green triangle button or press Ctrl+Enter, and you'll see a random number between 0 and 1 appear in the [x] column of the SPARQL query result. Because this function returns a different value each time you call it, go ahead and execute it a few more times.

Another built-in extension function is smf:parseDate(), which converts a string in a semi-structured date format into an xsd:date, xsd:dateTime, or xsd:time value. (To learn more about smf:random(), smf:parseDate(), and other available functions, select Help Contents from the Help menu and then TopBraid Composer -> Reference -> SPARQLMotion Functions Reference.) This function takes two parameters: a date string and a template showing which pieces of the date are where in that string. Try pasting the following query into the SPARQL

view and executing it:

LET (?x := smf:parseDate("12/3/09","MM/dd/yy")).

The value displayed under [x] is "2009-12-03". (The TopBraid Composer online help for this function includes the URL of a web page with greater detail about options for the format string in the smf:parseDate() function's second parameter.)

We're going build on this function to create a simpler function to convert dates in the MM/dd/yy format.

Defining your own functions

Before we use the SPIN vocabulary, we need to import it into our vocabulary. Open your Import

s view and drag the spin.owl file from the TopBraid/TBC folder in the Navigator view into the Import view. You'll see several new nodes appear in the Properties view, each with an sp: or spin: prefix and a plus sign next to it that expands the node to show the full range of SPIN properties. For now, you won't need to use these properties from this view, because TopBraid Composer gives you forms to fill out to specify everything you need to define a new function.

The Classes view also shows a few new classes. Click the plus sign next to spin:Modules to expand it, and you'll see that one of the subclasses is spin:Functions.

To create your new function,

  1. Right-click on spin:Functions and pick Create subclass from the context menu.

  2. On the "Create Classes" dialog box, click on the default new function name of "Functions_1", replace it with the name "mmddyy2ISO8601", and press Enter.

  3. Click the OK button. You'll see that your new subclass of spin:Functions is currently selected in the Classes view, and the class form will have the URI and rdfs:subClassOf values already filled out.

Your new function will have an argument passed to it: the date string to convert. The body of the function must reference this argument, so let's define the argument before creating the function body. Like everything else in SPIN, this definition will ultimately be stored with a series of triples, but because argument definition is so common in application development, SPIN includes a template to make it easier.

  1. SPIN models arguments to functions as constraints on those functions. On the mmddyy2ISO8601 class form, click the spin:constraint widget (the small white triangle to the right of the name "spin:constraint") and pick "Create from SPIN template".

  2. Select spl:Argument from the Available Ask/Construct Templates list, and then fill in the following two fields in the Arguments panel on the right of the "Create from SPIN template..." dialog box:

    • In the comment field, enter Convert mm/dd/yy formatted date to xsd:date type and format. (Remember to press the Enter key after entering a value on one of these forms. If you tab to another field and the comment field has a heavier border around it and and the "Create from SPIN template" dialog box's OK button is grayed out so that you can't click it, go back tot he comment field and press the Enter key.)

    • Instead of typing a value directly into the predicate field, click the plus sign to the right of it. This displays a "Select Resource..." dialog box; because we're defining our first (and only) argument to pass to the new mmddyy2ISO8601 function, click sp:arg1 on the right panel and then the OK button.

  3. Click the OK button to finish with the "Create from SPIN template" dialog box, and you'll see that the spin:constraint field of the class form for your new mmddyy2ISO8601 function has been filled out.

  4. All that remains is to define the function body. Click the spin:body widget on the class form and select Add empty row.

  5. Enter the following as the body:

    SELECT ?x
    WHERE {
    LET (?x := smf:parseDate(?arg1, "MM/dd/yy")) .

The body of this function uses ?x as the variable name, but you can use any name you want. If you have more than one variable, and it binds to more than one value, the function will return the first value of the first variable, so there's no point in naming more than one variable after the SELECT keyword.

Note how, in this SPARQL query, the first argument to the smf:parseDate() function is arg1, which we defined on the spin:constraint part of the form earlier.

Your new functions should be all ready. Test it by entering and executing the following in the SPARQL view:

LET (?x := :mmddyy2ISO8601("9/6/09")).

When you make calls to your own functions, don't forget the colon at the beginning of the function call and, if your function was not defined in the default namespace, the namespace prefix before that. All function calls are in a particular namespace (for example, parseDate() is in the namespace represented by the smf prefix), and your new mmddyy2ISO8601() function is in the default namespace for this project. For production application development, it's better to identify the function's namespace with a specific prefix, because it will be easier to import the code into another file without confusion.

mmddyy2ISO8601() is now a function that you can call anywhere, including from the body of new functions that you create. Test it further in the SPARQL view by passing other dates as a parameter.


This is a blog by TopQuadrant, developers of the TopBraid Suite, created to support the pursuit of our ongoing mission - to explode strange semantic myths, to seek out new models that support a new generation of dynamic business applications, to boldly integrate data that no one has integrated before.