Combining Rules with SPARQL

a recent blog-post by Dan Brickley reminded me that we have a Jena-Rule engine augmented with SPARQL dusting our shelves. Its years old, but may be interesting for you.

We augmented Jena’s rules by adding sparql.
The passing of parameters is easy, you just have to use the variables of the rules. Within Jena rules, you can always express graphs using N-Triple Axioms, so its also possible to write RDF files.
Only caveat: no quads.

code is in this folder
http://gnowsis.opendfki.de/browser/tags/0.8.3-alpha/gnowsis_retrieval/WEB-INF/src/org/gnowsis/retrieval/RuleQuerySparql.java

download SVN URI:
http://gnowsis.opendfki.de/repos/gnowsis/tags/0.8.3-alpha/gnowsis_retrieval/WEB-INF/src/org/gnowsis/retrieval/RuleQuerySparql.java

documentation:
http://gnowsis.opendfki.de/browser/tags/0.8.3-alpha/gnowsis_retrieval/doc/help.html

Here is a snippet of that documentation for you:

Inference

After the results have been gathered, inference rules are evaluated against the results.
This means, that you can define rules on which new information is generated
based on a declarative syntax described in the
Jena Rule Engine DOC.
An example file for these rules can be found in the source, at best directly in SVN here:
retrieval.rules.txt.
You can use the existing Jena rules and a special rule that was created by Leo Sauermann to
load additional triples from the gnowsis. This query-rule is defined as follows:

# Load triples from the search storage by a triple patter.
# The search storage is crawled by gnowsis IF you enabled it in the
# configuration and have crawled a few datasources. If not, this query
# will return nothing.

queryStorage(?subject, ?predicate, ?object, 'search')

# ?subject, ?predicate, ?object: a triple pattern. 
# Leave one of the empty (= a unbound variable like ?_x) and it will try to match 
# the empty thing as a wildcard. The variables are not bound in the pattern and
# cannot be used in the same rule. You have to write additional rules to work
# on the queried triples. 

usage example:
# load all project members and managers
(?project rdf:type org:Project) ->
queryStorage(?project, org:containsMember, ?_y, 'search'),
queryStorage(?project, org:managedBy, ?_z, 'search').

If you want to bind the variables and use them: It is not possible. See the
statement of the Jena developers
about this. But this is not a big problem, you can work around it easily.

Debugging Inference

If you want to tweak your inference rules and don’t want to have gnowsis run the query at all times,
you can use our built-in inference debugging tricks.

  • first: when you run the query for debugging, click the ‘rerun only rules’ link at the bottom of your search
  • second: open the inference file by clicking ‘edit rules file’
    (also found at the bottom of each search result)

the first stage brings you into a query mode, where pressing “reload” in the browser
just does the inference and the clustering, but not the search itself. This speeds up
your debugging of inference rules. You will only spot the difference in the addressbar
of the browser, which now contains something like http://…/retrieval?cmd=runrules&query=YourQuery

Also, note that syntax errors in your inference code will be logged to the gnowsis
logging system. This is either the message window, pane ‘org.gnowsis.retrieval.RetrievalService’
or your file logging in ~/.gnowsis/data/… .
You will not see syntax errors in your query results, sorry.

Inference and SPARQL combined

SPARQL reference

You can also use SPARQL queries to refine and expand the search results.
The basic syntax is to run a SPARQL query in the head of a rule, the first argument
is the query, escaped with ”, the following arguments are variables that will
be used in the query. The passed variables are interpreted as named variables
in the SPARQL query, named ?x1 ?x2 ?x3, etc.

Example for querySparql:

(?a ?b ?c) ->
querySparql('
 PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
 CONSTRUCT   { ?x1 rdfs:label ?label }
 WHERE       { ?x1 rdfs:label ?label }
')
', ?c).

The variable named ?x1 will be replaced with the value of ?c.

Note the
following tips:

  • literals are escaped using the \’text\’ markup.
  • All arguments passed after the query will be bound into the query using names ?x1, ?x2, …
  • querySparql can only be used in the head of rules.
  • Attention: if you are querying the gnowsis biggraph, you have to add the graph-name to your
    sparql queries.
  • Try out your queries on the debug interface before you use them.
  • Only ‘construct’ queries are supported, not select or describe.
  • Namespace prefixes: inside the SPARQL query, you can use the namespace prefixes defined in the rule file

An example to do so is given now, the task here is to retrieve the members of a project if a project
was in the result.

#note that these namespace prefixes are available in the sparql query
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix owl:  <http://www.w3.org/2002/07/owl#>.
@prefix retrieve: <http://www.gnowsis.org/ont/gnoretrieve#>.
@prefix tag: <http://www.gnowsis.org/ont/gnoretrievetag#>.

# get members with SPARQL
# note the special namspace defined inside
(?hit retrieve:item ?project),
(?project rdf:type org:Project) ->
querySparql('
PREFIX org: <http://km.dfki.de/model/org#>
CONSTRUCT   { 
  ?x1 org:containsMember ?m. ?m rdfs:label ?labelm. ?m rdf:type ?typem.
  ?x1 tag:todoRelateHitTo _:hit .
  _:hit rdf:type retrieve:InferedHit .
  _:hit retrieve:item ?m .
  _:hit retrieve:textSnippet \'member of project\'.
}
WHERE       { graph ?g {
  ?x1 org:containsMember ?m. ?m rdfs:label ?labelm. ?m rdf:type ?typem.
} }
', ?project).

# make the missing relations to the hits
# this is needed because you cannot pass blank nodes into the SPARQL engine.
(?item tag:todoRelateHitTo ?tohit),
(?hit retrieve:item ?item) ->
(?hit retrieve:related ?tohit).
run a sparql query, replacing placeholders (?x1, ?x2, ...) in the query with the passed arguments,
arguments have to be bound. Only 'construct' queries are supported.
 
# retrieve a test sparql
[test:
(http://xmlns.com/foaf/0.1/ ?x ?type)
-> querySparql('
CONSTRUCT   { ?x1 rdfs:label ?label }
WHERE       { ?x1 rdfs:label ?label. FILTER (?x1 = foaf:name) }
')
]

# retrieve with param - bind ?ont to the foaf ontology, it is called x1 in the query
[testbind:
(?ont rdf:type owl:Ontology)
-> querySparql('
CONSTRUCT   { ?p rdfs:isDefinedBy ?x1. ?p rdfs:label ?label. }
WHERE       { ?p rdfs:isDefinedBy ?x1. ?p rdfs:label ?label. }
', ?ont)
]


# example for gnowsis. note the use of "....{ graph ?g { ...."
[test:
(http://xmlns.com/foaf/0.1/ ?x ?type)
-> querySparql('
CONSTRUCT   { ?x1 rdfs:label ?label }
WHERE       { graph ?g {  ?x1 rdfs:label ?label. FILTER (?x1 = foaf:name) } }
')
]