Link Search Menu Expand Document
Start for Free

Query Functions

This page discusses implementing your own query functions.

Page Contents
  1. Overview
  2. Implementing Custom Functions
  3. Registering Custom Functions
  4. Using Custom Functions

Overview

The Stardog com.complexible.stardog.plan.filter.functions.Function interface is the extension point for section 17.6 (Extensible Value Testing) of the SPARQL spec.

Function corresponds to built-in expressions used in FILTER, BIND and SELECT expressions, as well as aggregate operators in a SPARQL query. Examples include && and || and functions defined in the SPARQL spec like sameTerm, str, and now.

Implementing Custom Functions

The starting point for implementing your own custom function is to extend AbstractFunction. This class provides much of the basic scaffolding for implementing a new Function from scratch.

If your new function falls into one of the existing categories, it should implement the appropriate marker interface:

  • com.complexible.stardog.plan.filter.functions.cast.CastFunction
  • com.complexible.stardog.plan.filter.functions.datetime.DateTimeFunction
  • com.complexible.stardog.plan.filter.functions.hash.HashFunction
  • com.complexible.stardog.plan.filter.functions.numeric.MathFunction
  • com.complexible.stardog.plan.filter.functions.rdfterm.RDFTermFunction
  • com.complexible.stardog.plan.filter.functions.string.StringFunction

If not, then it must implement com.complexible.stardog.plan.filter.functions.UserDefinedFunction. Extending one of these marker interfaces is required for the Function to be traverseable via the visitor pattern.

A zero-argument constructor must be provided which delegates some initialization to super, providing first the int number of required arguments followed by one or more URIs which identify the function. Any these URIs can be used to identify the function in a SPARQL query. The URIs are typed as String but should be valid URIs.

For functions which take a range of arguments, for example a minimum of 2, but no more than 4 values, a Range can be used as the first parameter passed to super rather than an int.

Function extends from Copyable, therefore implementations should also provide a “copy constructor” which can be called from the copy method:

private MyFunc(final MyFunc theFunc) {
    super(myFunc);
    // make copies of any local data structures
}

@Override
public MyFunc copy() {
    return new MyFunc(this);
}

Evaluating the function is handled by Value internalEvaluate(final Value...) The parameters of this method correspond to the arguments passed into the function; it’s the values of the variables for each solution of the query. Here we can perform whatever actions are required for our function. AbstractFunction will have already taken care of validating that we’re getting the correct number of arguments to the function, but we still have to validate the input. AbstractFunction provides some convenience methods to this end, for example assertURI and assertNumericLiteral for requiring that inputs are either a valid URI, or a literal with a numeric datatype respectively.

Errors that occur in the evaluation of the function should throw a com.complexible.stardog.plan.filter.ExpressionEvaluationException; this corresponds to the ValueError concept defined in the SPARQL specification.

Registering Custom Functions

Create a file called com.complexible.stardog.plan.filter.functions.Function in the META-INF/services directory with the name of your custom Function class.

Using Custom Functions

Functions are identified by their URI; you can reference them in a query using their fully-qualified URI, or specify prefixes for the namespaces and utilize only the qname. For this example, if the namespace tag:stardog:api: is associated with the prefix stardog and within that namespace we have our function myFunc we can invoke it from a SPARQL query as: bind(stardog:myFunc(?var) as ?tc)