Go to: Root TOC Topic TOC Previous Topic Next Topic
You can write a custom function in Java or Scala, upload a Scala source file or Java/Scala jar file, and call the function from within your SPARQL query code. This allows you unlimited flexibility to manipulate the data resulting from a SPARQL query.
Here is a comparison between the two packaging options:
| Feature | JAR File | Source File |
|---|---|---|
| Number of classes in same file | Multiple | One |
| Languages supported | Java/Scala | Only Scala |
| Dependencies supported | Yes | No |
| Pre-Compilation required | Yes | No |
| File name | Any | Must match class name |
Can use package directive |
Yes | No |
- Implement a new class that extends
org.apache.jena.sparql.function.Function, using Apache Jena 3.1.0. - Package it in a JAR File with any name -OR- just save it as
.scalafile. - If you have dependencies other than Jena libraries (e.g.
apache commons), include them in your JAR.
Upload your JAR File to the /meta/lib CM-Well folder.
-OR-
Upload your Scala source file to the /meta/lib/sources/scala CM-Well folder.
Note: Uploading a file to the
/meta/libfolder requires a security token.
- Under the
IMPORTsection in your SPARQL query, add your JAR name and path, relative to its mandatory location (meta/libormeta/lib/sources/scala). Make sure it ends with the correct suffix (".jar"or".scala"). - CM-Well registers your function as the URI
jar:<YourCanonicalFunctionName>. You can call it either directly as a URI, or by defining aPREFIX myJar: <jar:my.package.name.>.
The following example shows how to implement a function that adds a "42_" string prefix to any value, and call this function from within a SPARQL query.
Scala Code:
package cmwell.example
import org.apache.jena.sparql.engine.binding.Binding
import org.apache.jena.sparql.expr.{ExprList, NodeValue}
import org.apache.jena.sparql.expr.nodevalue.NodeValueString
import org.apache.jena.sparql.function.FunctionEnv
import scala.collection.JavaConversions._
class Add42 extends org.apache.jena.sparql.function.Function {
override def build(uri: String, args: ExprList): Unit = { }
override def exec(binding: Binding, args: ExprList, uri: String, env: FunctionEnv): NodeValue = {
val `var` = args.getList.headOption.getOrElse(new NodeValueString("arg0")).asVar()
val res: String = `var`.asNode() match {
case n if n.isURI => n.getURI
case n if n.isLiteral => n.getLiteral.toString()
case n if n.isVariable => Option(binding.get(`var`)).fold("Could not bind")(_.getLiteral.toString())
case _ => "???"
}
new NodeValueString("42_" + res)
}
}
Let's assume we have compiled this code using the following build configuration, and packaged it as Add42.jar.
scalaVersion := "2.12.4"
libraryDependencies ++= Seq(
"org.apache.jena" % "jena-arq" % "3.0.1"
)
The following command uploads the jar file to the correct CM-Well folder, using a valid security token:
curl <cm-well-host>/meta/lib/Add42.jar -H "X-CM-WELL-Type:File" \
-H "Content-Type:application/java-archive" --data-binary @Add42.jar \
-H "X-CM-WELL-TOKEN:[a valid token]"```
To call the function within a SPARQL query:
curl cmwell/_sp --data-binary '
PATHS
/example.org/Individuals2?op=search&length=1000&with-data
IMPORT
Add42.jar
SPARQL
SELECT DISTINCT ?name ?active ?res WHERE {
?name <http://www.tr-lbd.com/bold#active> ?active .
BIND( <jar:cmwell.example.Add42>(?active) as ?res).
} ORDER BY DESC(?name)'
Alternatively, you could save the same Scala code as Add42.scala, and upload it using this command:
curl <cm-well-host>/meta/lib/sources/scala/Add42.scala -H "X-CM-WELL-Type:File" \
-H "Content-Type:text/plain" --data-binary @Add42.scala \
-H "X-CM-WELL-TOKEN:[a valid token]"
You can then call the function as follows:
curl <cm-well-host>/_sp --data-binary '
PATHS
/example.org/Individuals2?op=search&length=1000&with-data
IMPORT
scala/Add42.scala
SPARQL
SELECT DISTINCT ?name ?active ?res WHERE {
?name <http://www.tr-lbd.com/bold#active> ?active .
BIND( <jar:Add42>(?active) as ?res).
} ORDER BY DESC(?name)'
Go to: Root TOC Topic TOC Previous Topic Next Topic