Stored Queries
This page discusses managing stored queries in Stardog - the capability to name and store SPARQL queries for future evaluation.
Page Contents
Overview
Stardog 4.2 added the capability to name and store SPARQL queries for future evaluation by referring to the query’s name.
Queries of any type can be stored in Stardog and executed directly by using the name of the stored query. Stored queries can be shared with other users, which gives those users the ability to run those queries provided that they have appropriate permissions for a database.
Stored queries can be managed via CLI, Java API, and HTTP API.
Storing Queries
Queries can be stored using the stored add
Stardog admin command and specifying a unique name for the stored query:
$ stardog-admin stored add -n types "select distinct ?type {?s a ?type}"
If a file is used to specify the query string without an explicit -n/--name
option then the name of the query file is used for the stored query:
$ stardog-admin stored add listProperties.sparql
By default, stored queries can be executed over any database, however, they can be scoped by providing a specific database name with the -d/--database
option. Also, by default, only the user who stored the query can access that stored query. Using the --shared
flag will allow other users to execute the stored query.
EXAMPLE
The following example stores a shared query with a custom name that can be executed over only the database myDb
:
$ stardog-admin stored add --shared -d myDb -n listProperties "select distinct ?p {?s ?p ?o}"
Stored query names must be unique for a Stardog instance. Existing stored queries can be replaced using the --overwrite
option in the command.
Updating Stored Queries
Queries can be updated using the --overwrite
option on the stored add
admin command and specifying an existing name for a stored query:
$ stardog-admin stored add --overwrite -n types "select distinct ?p {?s ?p ?o}"
Importing and Exporting Stored Queries
Stored queries are saved as RDF statements in the Stardog system database and it is possible to export the RDF representation of the queries:
Using the stored-export
command:
$ stardog-admin stored export
@prefix system: <http://system.stardog.com/> .
system:QueryExportAll a system:StoredQuery , system:SharedQuery ;
system:queryName "ExportAll" ;
system:queryString """construct where {?s ?p ?o}""" ;
system:queryCreator "admin" ;
system:queryDatabase "*" .
system:QuerylistDroids a system:StoredQuery , system:ReasoningQuery ;
system:queryName "listDroids" ;
system:queryString "select ?x { ?x a :Droid }" ;
system:queryCreator "luke" ;
system:queryDatabase "starwars" .
The same RDF representation can be used to import the stored queries as an alternative way of storing new queries or updating existing stored queries.
Using the stored-import
command:
$ stardog stored import queries.ttl
In addition to the built-in properties from the system
database arbitrary RDF properties can be used for stored queries. The value of these additional annotation properties should be IRIs or literals. Only the values directly linked to the stored query subject in the RDF document will be saved and the triples with a non-stored query subject will be ignored.
Running Stored Queries
Stored queries can be executed using the regular query execution CLI command by passing the name of the stored query:
$ stardog query execute myDb listProperties
Other commands like query explain
also accept stored query names. They can also be passed instead of query string into HTTP API calls.
Listing Stored Queries
To see all the stored queries, use the stored list
command:
$ stardog-admin stored list
The results are formatted tabularly:
+--------+-----------------------------------------+
| Name | Query String |
+--------+-----------------------------------------+
| graphs | SELECT ?graph (count(*) as ?size) |
| | FROM NAMED stardog:context:all |
| | WHERE { GRAPH ?graph {?s ?p ?o}} |
| | GROUP BY ?graph |
| | ORDER BY desc(?size) |
| people | CONSTRUCT WHERE { |
| | ?person a foaf:Person ; |
| | ?p ?o |
| | } |
| types | SELECT DISTINCT ?type ?label |
| | WHERE { |
| | ?s a ?type . |
| | OPTIONAL { ?type rdfs:label ?label } |
| | } |
+--------+-----------------------------------------+
3 stored queries
Users can only see the queries they’ve stored and the queries stored by other users that have been --shared
. The --verbose
option will show more details about the stored queries.
Removing Stored Queries
Stored queries can be removed using the stored remove
command:
$ stardog-admin stored remove storedQueryName
If you would like to clear all the stored queries then use the -a/--all
option:
$ stardog-admin stored remove -a
Stored Query Service
Stardog supports a way to invoke stored queries, including Path Queries in the context of another SPARQL query using the SERVICE
keyword. The Stored Query Service was released as beta in Stardog 7.3.2 and is generally availabile (GA) as of version 7.4.0. Previous versions of Stardog already employed the service mechanism in SPARQL to support full-text search and Entity Extraction and now this is naturally extended to stored queries.
Suppose, the following query is stored with the name “cities”:
$ stardog-admin stored add -n "cities" "SELECT ?country ?city { ?city :locatedIn ?country }"
Then it is possible to use it as a named view in another query:
prefix sqs: <tag:stardog:api:sqs:>
SELECT ?person ?city ?country {
SERVICE <query://cities> { [] sqs:vars ?country, ?city }
?person :from ?city
}
This query uses the “cities” query to look up information about the country given the city where a person lives. It is similar to using a Wikidata endpoint or an explicit subquery except that the subquery is referenced by name. The same query with an explicit subquery would look like this:
SELECT ?person ?city ?country {
{
SELECT ?country ?city {
?city :locatedIn ?country
}
}
?person :from ?city
}
Invoking stored queries by name has the major benefit that it avoids duplication of their query strings. Stored queries become reusable query building blocks maintained in one place rather than copy-pasted over the many queries which use them.
The body pattern of SERVICE <query://name> { ... }
specifies which variables of the stored query are used in the outer scope of the calling query. The sqs:vars
is a shortcut which is useful when stored query variables retain their names. However it’s possible to map stored query variable names to other identifiers to avoid naming conflicts:
prefix sqs: <tag:stardog:api:sqs:>
SELECT ?person ?city ?livesIn ?country {
SERVICE <query://countries> {
[] sqs:var:city ?livesIn ;
sqs:var:country ?country
}
?person :from ?livesIn ;
:born ?city
}
Furthermore, it’s possible to statically bind some stored query variables to constants so the query would behave like a parameterized view:
prefix sqs: <tag:stardog:api:sqs:>
SELECT ?city ?country {
SERVICE <query://countries> {
[] sqs:var:city ?city ;
sqs:var:country :The_United_States
}
}
Another interesting feature is the ability to call path queries from SELECT
/CONSTRUCT
/ASK
queries. One cannot directly use a path query in a subquery because those do not return SPARQL binding sets, aka solutions (we discussed that issue in an earlier blog post on Extended Solutions). However, this service circumvents that restriction:
prefix sqs: <tag:stardog:api:sqs:>
SELECT ?start (count(*) as ?paths) {
SERVICE <query://paths> {
[] sqs:vars ?start
}
} GROUP BY ?start
The stored path query returns paths (according to some VIA
pattern) and uses ?start
as the start node variable. The main query aggregates the returned paths by the start node and returns the number of paths for each. In contrast to the earlier SELECT
example, this would not be possible directly because path queries cannot be used as subqueries.
One should be aware of the potential explosive nature of path queries when using them through the stored query service. They can return a very high number of paths to be joined or aggregated and thus create substantial memory pressure on the server.
Stardog 7.3.2+ supports two new SPARQL functions which take paths as the argument: stardog:length
and stardog:nodes
. The former returns the length of the path and the latter generates a comma-separated string of all path nodes. Since SELECT query results do not support paths as first-class citizens (that is, any value in a binding set is either an IRI or a literal or a blank node), these provide means to return path information by generating literals. Paths returned by the stored query service can be accessed via the reserved variable name ?path
:
prefix sqs: <tag:stardog:api:sqs:>
prefix stardog: <tag:stardog:api:>
SELECT ?start (avg(stardog:length(?path)) as ?avg_length) {
SERVICE <query://paths> {
[] sqs:vars ?start, ?path
}
} GROUP BY ?start
Stardog 7.4.4 supports additional stardog:all
and stardog:any
functions to check Boolean conditions over edges in paths returned by a stored path query. These are useful for filtering path query results on the server side:
prefix sqs: <tag:stardog:api:sqs:>
prefix stardog: <tag:stardog:api:>
SELECT (str(stardog:nodes(?path))) {
SERVICE <query://paths> {
[] sqs:vars ?path
}
FILTER(stardog:all(?path, ?attribute = 10))
}
Here ?attribute
is a variable occurring in the VIA pattern of the stored path query. stardog:all
returns true
if the ?attribute = 10
condition is true
for all edges in the path. The second argument can be an arbitrary SPARQL expression. stardog:any
is the complementary function returning true
if the condition is true
for at least one edge. It is particularly useful for querying paths which must pass through a particular node(s) in the graph.