twinql API reference

Table of Contents

Introduction

Valid result formats

Exported functions

Extension functions

SELECT bindings and ASK results

SPARQL and first-class triples

Function index

Introduction

This document describes twinql, AllegroGraph's SPARQL implementation. Each of the following functions is exported from the db.agraph.sparql package. This package has sparql and twinql as nicknames.

For notes on twinql's conformance to the W3C specification please see this document.

You might also want to look at the reference guide for AllegroGraph and the AllegroGraph tutorial.

Conceptually, twinql has three layers:

Currently, input and output from each of these layers is limited (for example, the query plan is not available to user code, but parsed output is). This will change in a future release.

Valid result formats

There are three possible outputs from a SPARQL query:

twinql provides a number of different ways to serialize these results to a stream, provided as keyword symbols to the query functions. The results-format argument controls how ASK and SELECT query results are serialized; some possible formats are :sparql-xml, which serializes the result into the SPARQL XML result format, and :sparql-json, which uses the JSON format.

For CONSTRUCT and DESCRIBE, the value of the rdf-format argument applies.

The default formats are :sparql-xml and :rdf/xml respectively. Providing an unrecognized format will signal an error.

You can find out which formats are allowed for a particular verb by using get-allowed-results-formats and get-allowed-rdf-formats.

Exported functions

parse-sparql string &optional sparql.parser::default-prefixes sparql.parser::default-base
function

parse-sparql takes a string and parses it into an s-expression format. A parse error will result in a sparql-parse-error being raised.

This function is useful for three reasons: validation and inspection of queries, manual manipulation of query expressions without text processing, and performing parsing at a more convenient time than during query execution.

You do not need an open triple store in order to parse a query.

default-base and default-prefixes allow you to provide BASE and PREFIX arguments to the parser without inserting them textually into the query.

default-base should be nil or a string, and default-prefixes can either be a hash-table (string prefix to string expansion) or a list similar to db.agraph:*standard-namespaces*.

parse-sparql returns the s-expression representation of the query string.

run-sparql query &rest args &key from from-named limit offset default-base default-prefixes db rdf-format results-format with-variables default-dataset-behavior output-stream extendedp memoizep memos load-function verbosep
function

run-sparql takes a SPARQL query as input and returns bindings or new triples as output.

SELECT and ASK query results will be presented in results-format; the RDF output of DESCRIBE and CONSTRUCT will be serialized according to rdf-format. If the format is programmatic, any results will be returned as the first value, and nothing will be printed on output-stream.

  • query can be a string, which will be parsed by parse-sparql, or an s-expression as produced by parse-sparql. If you expect to run a query many times, you can avoid some parser overhead by parsing your query once and calling run-sparql with the parsed representation.

  • If query is a string, then default-base and default-prefixes are provided to parse-sparql to use when parsing the query. See the documentation for that function for details. Parser errors can be signaled within parse-sparql, and will be propagated onwards by run-sparql.

  • Results or new triples will be serialized to output-stream. If a programmatic format is chosen for output, the stream is irrelevant. An error will be signaled if output-stream is not a stream, t, or nil.

  • If limit, offset, from, or from-named are provided, they override the corresponding values specified in the query string itself. As FROM and FROM NAMED together define a dataset, and the SPARQL Protocol specification states that a dataset specified in the protocol (in this case, the programmatic API) overrides that in the query, if either from or from-named are non-nil then any dataset specifications in the query are ignored. You can specify that the contents of the query are to be partially overridden by providing t as the value of one of these arguments. This is interpreted as 'use the contents of the query'. from and from-named should be lists of URIs.

  • default-dataset-behavior controls how the query engine builds the dataset environment if FROM or FROM NAMED are not provided. Valid options are :all (ignore graphs; include all triples) and :default (include only the triple store's default graph).

  • with-variables should be an alist of symbols and values. Before the query is executed, the variables named after symbols will be bound to the provided values. This allows you to use variables in your query which are externally imposed, or generated by other queries. The format expected by with-variables is the same as that used for each element of the list returned by the :alists results-format.

  • db (*db* by default) specifies the triple store against which queries should run.

  • If verbosep is non-nil, status information is written to *sparql-log-stream* (*standard-output* by default).

Three additional extensions are provided for your use.

  • If extendedp is true (or *use-extended-sparql-verbs-p* is true, and the argument omitted) some additional SPARQL verbs become available. SUM, AVERAGE, MEDIAN, STATS, CORRELATION, and COUNT can all be used in place of SELECT. These verbs are still experimental and undocumented.

  • If memoizep is true (or *build-filter-memoizes-p* is true, and the argument omitted) calls to SPARQL query functions (such as STR, fn:matches, and extension functions) will be memoized for the duration of the query. For most queries this will yield speed increases when FILTER or ORDER BY are used, at the cost of additional memory consumption (and consequent GC activity). For some queries (those where repetition of function calls is rare) the cost of memoization will outweigh the benefits. In large queries which call SPARQL functions on many values, the size of the memos can grow large.

Memoization also requires that your extension functions do not depend on side-effects. The standard library is correct in this regard.

  • You can achieve substantial speed increases by sharing your memos between queries. Create a normal eql hash-table with (make-hash-table), passing it as the value of the memos argument to run-sparql. This hash-table will gradually fill with memos for each used query function.

If you wish to globally enable memoization, set the variables as follows:

(progn  
  (setf *build-filter-memoizes-p* t)  
  (setf *sparql-sop-memos* (make-hash-table))) 

Be aware that the size of *sparql-sop-memos* could grow very large indeed. You might consider using a weak hash-table, or periodically discarding the contents of the hash-table.

  • load-function is a function with signature (uri db &optional type) or nil. If it is a function, it is called once for each FROM and FROM NAMED parameter making up the dataset of the query. The execution of the query commences once each parameter has been processed. The type argument is either :from or :from-named, and the uri argument is a part (ordinarily a future-part) naming a URI. The default value is taken from *dataset-load-function*. You can use this hook function to implement loading of RDF before the query is executed.

The values returned by run-sparql are dependent on the verb used. The first value is typically disregarded in the case of results being written to output-stream. If output-stream is nil, the first value will be the results collected into a string (similar to the way in which cl:format operates).

The second value is the query verb: one of :select, :ask, :construct, or :describe. Other values are possible in extended mode.

The third value, for SELECT queries only, is a list of variables. This list can be used as a key into the values returned by the :arrays and lists results formats, amongst other things.

Individual results formats are permitted to return additional values.

run-sparql-select query format &key ordered distinct from from-named limit offset with-variables output-stream variables
function

Run the provided query, serializing the results as specified by the format argument. :distinct can be t or :distinct, meaning full DISTINCT processing, or :reduced, which optionally discards duplicates.

See the documentation for run-sparql for more information.

Return a list of alists, each of which contains the values for variables in order. If variables is not provided, you can find the variables as the second return value.

Return a list of lists, each of which contains the values for variables in order. If variables is not provided, you can find the variables as the second return value.

run-sparql-ask query format &key from from-named with-variables output-stream
function
Run the provided query, serializing the results as specified by the format argument. See the documentation for run-sparql for more information.

run-sparql-describe targets query rdf-format &key variables with-variables from from-named output-stream
function

Run the provided query, using the results to construct a new graph. The new graph is either returned or serialized onto output-stream as specified by the format argument. targets is a list of resources to describe. query is used as input to run-sparql-select to yield further resources to describe.

See the documentation for run-sparql for more information.

run-sparql-construct construct-pattern query-pattern rdf-format &key ordered from from-named limit offset with-variables output-stream
function

Run the provided query, using the results to construct a new graph. The new graph is either returned or serialized onto output-stream as specified by the format argument. construct-pattern must be a list of triple patterns. query-pattern is used as input to run-sparql-select.

See the documentation for run-sparql for more information.

UPI coercion depends on the current value of db!

get-allowed-results-formats &optional verb
function
Returns a list of keyword symbols that are valid when applied as values of results-format to a query with the given verb. if verb is not provided, the intersection of :ask and :select (the two permitted values) is returned.

get-allowed-rdf-formats &optional verb
function
Returns a list of keyword symbols that are valid when applied as values of rdf-format to a query with the given verb. if verb is not provided, the intersection of :construct and :describe (the two permitted values) is returned.

Extension functions

SPARQL allows for query engines to associate extension functions with URIs, and call them from within queries.

You can define your own URI functions in twinql through defurifun, or associate existing functions with a URI through associate-function-with-uri. defurifun does some manipulation of the arguments, so you should use it whenever possible.

associate-function-with-uri function sparql.sop::uri &key sparql.sop::cache-now-p
function
Assert a mapping between uri, which is a string or a valid part, and the provided function, which is a symbol or a function. If cache-now-p, and function is a symbol, its function binding is stored instead of the symbol itself.

print-function-uri-mappings &key stream sparql.sop::db
function
Print all mappings between URIs and functions to stream (*standard-output* by default).

defurifun name sparql.sop::uri sparql.sop::args &body sparql.sop::body
macro
Define a new function, name, and associate it with uri as with associate-function-with-uri. args is not evaluated, exactly as with defun.

Here's an example: a function that will do an HTTP HEAD request against the provided URL, returning the HTTP status code as an integer literal, or 0 if there's a problem.

(The built-in functions are quite robust, so a Lisp integer will be treated as an RDF literal with data type xsd:integer.)

(defurifun ex-head-request !<http://example.com/fn/head> (uri)  
  (or  
    (when uri  
      (ignore-errors  
        (format t "~&Performing HTTP HEAD request on <~A>...~%"  
                  (upi->value uri))  
        (second  
          (multiple-value-list  
            (net.aserve.client:do-http-request (upi->value uri)  
                                               :method :head)))))  
    0))  
   
    

You can use this function in a query exactly as you would a built-in function.

Using this data as an example:

<http://ex.com/a> <http://ex.com/foo> "200"^^<http://www.w3.org/2001/XMLSchema#integer> .  
    

we can run a query like so:

sparql(54): (run-sparql  
"  
PREFIX f: <http://example.com/fn/>  
SELECT ?x {  
  ?x <http://ex.com/foo> ?y .  
  FILTER ( ?y = f:head("http://franz.com\") )  
}"  
  :results-format :count)  
    

which produces this output:

Performing HTTP HEAD request on <http://franz.com>...  
1  
:select  
(?x)  
    

… we know, then, that franz.com is returning a 200 status code.

Note that these filter functions can be called an arbitrary number of times during the execution of a query. It's not a good idea to actually perform expensive operations like HTTP requests in your queries.

SELECT bindings and ASK results

run-sparql allows you programmatic access to results in a number of ways.

Any of the following results-formats are suitable as arguments to SELECT or ASK queries:

The following results-formats are suitable as arguments to SELECT queries:

The following results-formats are suitable as arguments to ASK queries:

Any of the following rdf-formats are suitable as arguments to CONSTRUCT or DESCRIBE queries:

The following rdf-format is suitable for DESCRIBE queries:

The following rdf-format is suitable for CONSTRUCT queries:

You can use get-allowed-results-formats and get-allowed-rdf-formats to access these allowed values dynamically at run-time.

Variables

Programmatic results associate values with variables. Variables are parsed into symbols by the query parser.

The mapping from variables to symbols is straightforward, and best illustrated by example:

If you provide variables in a with-variables argument, a leading ? is prepended to the variable name. Your queries will run correctly if you provide them as s-expressions and do not prepend ?, but:

All variables created by the parser are interned in the current package, as if by a call to cl:intern. You should adhere to these rules when processing results or providing bindings using with-variables.

SPARQL and first-class triples

AllegroGraph permits you to make assertions about triple IDs (UPIs of type triple-id). SPARQL offers no support for this: only named graphs are supported. First-class triples are entirely outside the scope of both RDF and SPARQL.

SPARQL queries against stores using first-class triples are not supported. twinql makes only limited provisions for such queries:

It bears repeating that SPARQL is not intended to work with first-class triples; any queries that run successfully are little more than accidents, and named graphs are a better choice in all cases.

Function index