Clone URL (Committers only): https://cms.apache.org/redirect?new=anonymous;action=diff;uri=http://jena.apache.org/documentation%2Fquery%2Fwriting_propfuncs.mdtext
Rob Hall Index: trunk/content/documentation/query/writing_propfuncs.mdtext =================================================================== --- trunk/content/documentation/query/writing_propfuncs.mdtext (revision 0) +++ trunk/content/documentation/query/writing_propfuncs.mdtext (working copy) @@ -0,0 +1,141 @@ +Title: ARQ - Writing Property Functions +Notice: Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +**ARQ - Writing Property Functions** + +See also [Writing Filter Functions](writing_functions.html). + +Applications can add SPARQL property functions to the query engine. This is done by first implementing the + [`PropertyFunction`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/pfunction/PropertyFunction.html) + interface, and then either registering that function or using the fake `java:` URI scheme to dynamically + load the function. + +**Writing SPARQL Property Functions** + +Similar to SPARQL Filter Functions, a SPARQL Property Function is an extension point of the SPARQL query language + that allows a URI to name a function in the query processor. A key difference is that Property Functions may + generate new bindings. + +Just like + [com.hp.hpl.jena.sparql.function.Function](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/function/Function.html) + there are various utility classes provided to simplify the creation of a Property Function. The selection of + one depends on the 'style' of the desired built-in. For example, `PFuncSimple` is expected to be the predicate + of triple patterns `?such ex:as ?this`, where neither argument is an `rdf:list`, and either may be a variable. + Alternatively, `PFuncAssignToObject` assumes that the subject will be bound, while the object will be a variable. + + PropertyFunction + | + |--PropertyFunctionBase + | + |--PropertyFunctionEval + | + |--PFuncSimpleAndList + | + |--PFuncSimple + | + |--PFuncAssignToObject + | + |--PFuncAssignToSubject + +The choice of extension point determines the function signature that the developer will need to implement, and + primarily determines whether some of the arguments will be + [`com.hp.hpl.jena.graph.Node`](https://jena.apache.org/documentation/javadoc/jena/com/hp/hpl/jena/graph/Node.html)s or + [`com.hp.hpl.jena.sparql.pfunction.PropFuncArg`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/pfunction/PropFuncArg.html)s. + In the latter case, the programmer can determine whether the argument is a list as well as how many + arguments it consists of. + + +**Registration** + +Every property function is associated with a particular + [`com.hp.hpl.jena.sparql.util.Context`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/util/Context.html). + This allows you to limit the availability of the function to be global or associated with a particular dataset. + For example, a custom Property Function may expose an index which only has meaning with respect to some set + of data. + +Assuming you have an implementation of + [`com.hp.hpl.jena.sparql.pfunction.PropertyFunctionFactory`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/pfunction/PropertyFunctionFactory.html) + (shown later), you can register a function as follows: + + + final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ARQ.getContext()); + reg.put("urn:ex:fn#example", new ExamplePropertyFunctionFactory); + PropertyFunctionRegistry.set(ARQ.getContext(), reg); + + +The only difference between global and dataset-specific registration is where the `Context` object comes from: + + final Dataset ds = DatasetFactory.createMem(); + final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ds.getContext()); + reg.put("urn:ex:fn#example", new ExamplePropertyFunctionFactory); + PropertyFunctionRegistry.set(ds.getContext(), reg); + +Note that + [`com.hp.hpl.jena.sparql.pfunction.PropertyFunctionRegistry`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/pfunction/PropertyFunctionRegistry.html) + has other `put` methods that allow registration by passing a `Class` object, as well. + +**Implementation** + +The implementation of a Property Function is actually quite straight forward once one is aware of the tools + at their disposal to do so. For example, if we wished to create a Property Function that returns no results + regardless of their arguments we could do so as follows: + + public class ExamplePropertyFunctionFactory implements PropertyFunctionFactory { + @Override + public PropertyFunction create(final String uri) + { + return new PFuncSimple() + { + @Override + public QueryIterator execEvaluated(final Binding parent, final Node subject, final Node predicate, final Node object, final ExecutionContext execCxt) + { + return QueryIterNullIterator.create(execCtx); + } + }; + } + } + +`Node` and `PropFuncArg` objects allow the developer to reflect on the state of the arguments, and choose what + bindings to generate given the intended usage of the Property Function. For example, if the function expects a + list of three bound arguments for the object of the property, then it can throw a `ExprEvalException` + (or derivative) to indicate incorrect use. It is the responsability of the developer to identify what parts + of the argument are bound, and to respond appropriately. + +For example, if `?a ex:f ?b` were a triple pattern in a query, it could be called with `?a` bound, `?b` bound, + or neither. It may make sense to return new bindings that include `?b` if passed a concrete value for `?a`, + or conversely to generate new bindings for `?a` when passed a concrete `?b`. If both `?a` and `?b` are bound, + and the function wishes to confirm that the pairing is valid, it can return the existing binding. If there are + no valid solutions to return, then an empty solution may be presented. + +There are several extremely useful implementations of `QueryIterator` within the Jena library that make it +easy to support typical use cases. + +Of particular note: + + - [`QueryIterNullIterator`](https://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/engine/iterator/QueryIterNullIterator.html) - to indicate that there are no valid solutions/bindings for the given values + - [`QueryIterSingleton`](https://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/engine/iterator/QueryIterSingleton.html) - to provide a single solution/binding for the given values + - [`QueryIterPlainWrapper`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/engine/iterator/QueryIterPlainWrapper.html) - to provide multiple solutions/bindings for the given values + +The second two cases require instances of `Binding` objects which can be obtained through static methods of + [`BindingFactory`](http://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/engine/binding/BindingFactory.html). + Creation of `Binding` objects will also require references to [`Var`](https://jena.apache.org/documentation/javadoc/arq/com/hp/hpl/jena/sparql/core/Var.html) + and [`NodeFactory`](https://jena.apache.org/documentation/javadoc/jena/com/hp/hpl/jena/graph/NodeFactory.html) + +Note that it can make a lot of sense to generate the `Iterator<Binding>` for `QueryIterPlainWrapper` by means of + Jena's `ExtendedIterator`. This can allow domain-specific value to be easily mapped to `Binding` objects in + a lazy fashion. \ No newline at end of file Property changes on: trunk/content/documentation/query/writing_propfuncs.mdtext ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
