A simple SPIN rule doesn't work in RDF4J - semantic-web

I've just started using the triple store RDF4J (I am using its workbench, version 2.3.1, run on Windows 10 with Tomcat 9.0)
I want to use the SPIN rules in RDF4J. Therefore, I created a new repository (In memory with RDFS+SPIN support).
I wanted to start with the SPIN example in RDF4J documentation concerning how to add SPIN rules. That is, I added the data (in Turtle, and imported to RDF4J)
#prefix ex: <http://example.org/>.
ex:John a ex:Father ;
ex:parentOf ex:Lucy .
ex:Lucy a ex:Person .
And the rule:
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
#prefix sp: <http://spinrdf.org/sp#>.
#prefix spin: <http://spinrdf.org/spin#>.
#prefix ex: <http://example.org/>.
ex:Person a rdfs:Class ;
spin:rule [
a sp:Construct ;
sp:text """PREFIX ex: <http://example.org/>
CONSTRUCT { ?this ex:childOf ?parent . }
WHERE { ?parent ex:parentOf ?this . }"""
] .
And as instructed in the documentation, I exposed the query (with the checkbox 'Include inferred statements' checked),
PREFIX ex: <http://example.org/>
SELECT ?child
WHERE { ?child ex:childOf ?parent }
However, no result returned:
Could someone, please tell me am I doing something wrong, why the SPIN rule doesn't work in my RDF4J workbench, have I missed something?

(reposting my comment as an answer for future readers)
The SPIN reasoner currently assumes that all data is in the default context, I think. Make sure that your data was not added to a named graph.

Related

How to direct RDF4J to use SPIN RDF triples when sp:text is present in imported RDF file?

I'm using RDF4J server and workbench version 2.2.2. I'm using a SPIN-capable repository in RDF4J, and I'm reading an RDF file I've created in TobBraid Composer Free Edition (TBC FE) containing many spin:construct rules. TBD FE is set to include the SPARQL source code for my constructors via the sp:text property. I've observed that, when the sp:text triple is present making the SPARQL source code available to RDF4J, RDF4J appears to use the SPARQL source instead of using the RDF tokenized representation of the same query. My primary and secondary questions are:
How can I direct RDF4J to use the RDF representation of a SPIN constructor when both the sp:text and the RDF representation are present in the imported RDF file?
If RDF4J uses the sp:text representation of a SPIN constructor, how can it be directed to use the prefix definitions present at the head of the imported RDF file? I have 69 constructors so far and counting. Although I can embed prefix definitions in each constructor, it seems wasteful to do so.
When I deprive RDF4J of the sp:text SPARQL source code representation, the constructors run as expected using prefixes defined at the head of the imported RDF file. I can deprive RDF4J of the source code by executing a query to delete to the source code before I instantiate the class for which I have defined a constructor. I've used this SPARQL update query to accomplish that end:
PREFIX sp: <http://spinrdf.org/sp#>
DELETE {?s sp:text ?o .} WHERE {?s sp:text ?o .}
I'd like to keep the SPARQL source code around for display purposes in a GUI I'm building that communicates with the RDF4J server via SPARQL queries. My awkward interim fix is to substitute another custom data property for the sp:text property using the SPARQL update query used in step 5 below. This property substitution successfully prevents RDF4J from finding the SPARQL source code for the SPIN constructors. RDF4J then interprets the tokenized RDF representation of the rule instead. Is there a cleaner way to force RDF4J to execute SPIN constructors from the RDF instead of from the SPARQL source code? I'm thinking there must be some way to signal RDF4J to interpret the RDF representation instead of the SPARQL source code, but I don't know how.
And now the gory details to make this situation reproducible...
Create a SPIN-capable repository in RDF4J using RDF4J workbench. Mine is named TakeRDF4J4SPIN (Repositories → New Repository)
Clear the repository using RDF4J workbench (Modify → Clear)
Load pub7.rdf using RDF4J workbench... (Modify → Add w/ use base URI as context identifier unchecked)
Note that this RDF file defines all relevant prefixes at the head of the file:
<?xml version="1.0"?>
<rdf:RDF
xmlns:fn="http://www.w3.org/2005/xpath-functions#"
xmlns:soo="http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#"
xmlns:spolicy="http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/spolicy#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:spin="http://spinrdf.org/spin#"
xmlns:sp="http://spinrdf.org/sp#"
xmlns:smf="http://topbraid.org/sparqlmotionfunctions#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:arg="http://spinrdf.org/arg#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:pub7="http://www.disa.mil/dso/a2i/ontologies/PBSM/Interface/Pub7#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:spl="http://spinrdf.org/spl#"
xml:base="http://www.disa.mil/dso/a2i/ontologies/PBSM/Interface/Pub7">
Also note that the SPIN constructor attached to the class pub7:Pub7TestClass is:
CONSTRUCT {
?this spin:hasConstraintViolation _:b0 .
_:b0 a spin:ConstraintViolation ;
rdfs:label "Test message." ;
spin:violationRoot ?this ;
spin:violationLevel spin:Error ;
spolicy:sPActionRecordHasTimestamp ?timestamp .
}
WHERE {
BIND(now() AS ?timestamp) .
}
Attempt to create an instance of pub7:Pub7TestClass...
I use this SPARQL update query in RDF4J workbench's Modify → SPARQL Update to create the instance...
PREFIX inst: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/Instantiations#>
PREFIX pub7: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Interface/Pub7#>
INSERT DATA {
inst:aPub7TestClassInstance_test1 a pub7:Pub7TestClass .
}
Which should result in an prefix undefined error reported in RDF4J workbench due to attempting to execute the above constructor based on the sp:text SPARQL source code representation:
org.eclipse.rdf4j.query.UpdateExecutionException: org.eclipse.rdf4j.repository.RepositoryException: org.eclipse.rdf4j.sail.SailException: org.eclipse.rdf4j.query.MalformedQueryException: org.eclipse.rdf4j.query.parser.sparql.ast.VisitorException: QName 'spin:hasConstraintViolation' uses an undefined prefix
Now hide the SPIN constructors' sp:text from RDF4J using the following SPARQL update query:
.
PREFIX sp: <http://spinrdf.org/sp#>
PREFIX soo: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#>
DELETE {
?originalPolicyURI sp:systemProperty ?policySourceCodeString .
?originalPolicyURI sp:text ?policySourceCodeString .
}
INSERT {
?originalPolicyURI soo:policySourceCode ?policySourceCodeString .
}
WHERE {
?originalPolicyURI sp:text ?policySourceCodeString .
}
Now re-run the SPARQL update query shown in step 4 to instantiate the test class. The update query should run without errors this time.
Now use RDF4J Workbench's Explore → Explore function to look at the instantiation/individual we just created, inst:aPub7TestClassInstance_test1. One should see that the instantiation has a constraint violation notice via the spin:hasConstratintViolation property, providing evidence that the test constructor did indeed run this time absent the sp:text representation, forced to use the RDF tokenized representation of the SPIN constructor.
I have a partial, inelegant work-around to address my secondary question about including prefixes in the spin rules. As an initialization step, I run the following SPARQL update query that adds needed prefixes to each of the sp:text strings. Of course, this work-around is limited since the query embeds the prefix mappings I'm using. If other prefixes were required, then the query below would need to be edited to embed the new query definitions.
Here's the SPARQL Update query I'm using as an initialization step after my class/rule/property definition ontologies have been loaded into RDF4J but before I load my instantiations ontology is loaded. (Timing is critical since the instantiations ontology begins invoking SPIN constructors.)
PREFIX sp: <http://spinrdf.org/sp#>
DELETE {
?rule sp:text ?ruleText .
}
INSERT {
?rule sp:text ?newRuleText .
}
WHERE {
?rule sp:text ?ruleText .
BIND (IF (CONTAINS(?ruleText, "fn:"), "PREFIX fn: <http://www.w3.org/2005/xpath-functions#>\n","")
AS ?prefixComponent00) .
BIND (IF (CONTAINS(?ruleText, "owl:"), "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n","")
AS ?prefixComponent01) .
BIND (IF (CONTAINS(?ruleText, "spin:"), "PREFIX spin: <http://spinrdf.org/spin#>\n","")
AS ?prefixComponent02) .
BIND (IF (CONTAINS(?ruleText, "spl:"), "PREFIX spl: <http://spinrdf.org/spl#>\n","")
AS ?prefixComponent03) .
BIND (IF (CONTAINS(?ruleText, "sp:"), "PREFIX sp: <http://spinrdf.org/sp#>\n","")
AS ?prefixComponent04) .
BIND (IF (CONTAINS(?ruleText, "par:"), "PREFIX par: <http://parliament.semwebcentral.org/parliament#>\n","")
AS ?prefixComponent05) .
BIND (IF (CONTAINS(?ruleText, "rdf:"), "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n","")
AS ?prefixComponent06) .
BIND (IF (CONTAINS(?ruleText, "rdfs:"), "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n","")
AS ?prefixComponent07) .
BIND (IF (CONTAINS(?ruleText, "time:"), "PREFIX time: <http://www.w3.org/2006/time#>\n","")
AS ?prefixComponent08) .
BIND (IF (CONTAINS(?ruleText, "xsd:"), "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\n","")
AS ?prefixComponent09) .
BIND (IF (CONTAINS(?ruleText, "geo:"), "PREFIX geo: <http://www.opengis.net/ont/geosparql#>\n","")
AS ?prefixComponent10) .
BIND (IF (CONTAINS(?ruleText, "geof:"), "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>\n:","")
AS ?prefixComponent11) .
BIND (IF (CONTAINS(?ruleText, "inst:"), "PREFIX inst: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/Instantiations#>\n","")
AS ?prefixComponent12) .
BIND (IF (CONTAINS(?ruleText, "pub7:"), "PREFIX pub7: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Interface/Pub7#>\n","")
AS ?prefixComponent13) .
BIND (IF (CONTAINS(?ruleText, "pub8:"), "PREFIX pub8: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Interface/Pub8#>\n","")
AS ?prefixComponent14) .
BIND (IF (CONTAINS(?ruleText, "soo:"), "PREFIX soo: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/SpectrumOperationsOntology#>\n","")
AS ?prefixComponent15) .
BIND (IF (CONTAINS(?ruleText, "spolicy:"), "PREFIX spolicy: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/spolicy#>\n","")
AS ?prefixComponent16) .
BIND (IF (CONTAINS(?ruleText, "sharing:"), "PREFIX sharing: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/sharing#>\n","")
AS ?prefixComponent17) .
BIND (IF (CONTAINS(?ruleText, "dd1494:"), "PREFIX dd1494: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/dd1494#>\n","")
AS ?prefixComponent18) .
BIND (IF (CONTAINS(?ruleText, "Nuvio:"), "PREFIX Nuvio: <http://cogradio.org/ont/Nuvio.owl#>\n","")
AS ?prefixComponent19) .
BIND (IF (CONTAINS(?ruleText, "CRO2:"), "PREFIX CRO2: <http://cogradio.org/ont/CRO2.owl#>\n","")
AS ?prefixComponent20) .
BIND (IF (CONTAINS(?ruleText, "olo:"), "PREFIX olo: <http://purl.org/ontology/olo/core#>\n","")
AS ?prefixComponent21) .
BIND (CONCAT(
?prefixComponent00,
?prefixComponent01,
?prefixComponent02,
?prefixComponent03,
?prefixComponent04,
?prefixComponent05,
?prefixComponent06,
?prefixComponent07,
?prefixComponent08,
?prefixComponent09,
?prefixComponent10,
?prefixComponent11,
?prefixComponent12,
?prefixComponent13,
?prefixComponent14,
?prefixComponent15,
?prefixComponent16,
?prefixComponent17,
?prefixComponent18,
?prefixComponent19,
?prefixComponent20,
?prefixComponent21
) AS ?prefixes ) .
BIND (CONCAT(?prefixes, "\n", ?ruleText) AS ?newRuleText) .
}
It is possible that the query above could include a prefix definition based on a false positive if the prefix definition happened to be contained in an embedded string or comment. For example, the literal "Greg’s solo: five measures"^^xsd:string would cause the above query to include the definition of the olo: prefix, perhaps needlessly. However, inclusion of non-required prefixes had no major impact on performance and no impact on correctness. One could do better by using regular expression in place of the simple CONTAINS matches in the query above.

SPARQL Path between two nodes

Given a graph:
#prefix da: <http://example.com/data/> .
#prefix on: <http://example.com/on/> .
da:Shenaz on:husband da:Javed .
da:Rita on:friend da:Noor ;
on:sister da:Tom .
da:Noor on:sister da:Shenaz .
da:Javed on:child da:Jaabir .
da:Tom on:sister da:James .
da:Jaabir on:grandFather da:Rafick .
There is a path between da:Noor and da:James which is da:Noor ^on:friend/on:sister/on:sister da:James . but the following query is returning false
PREFIX da: <http://example.com/data/>
PREFIX on: <http://example.com/on/>
ASK {
da:Noor ((<>|!<>)|^(<>|!<>))* da:James .
}
It is a possible bug in Jena, with RDFLib in Python, True is returned
For some reason the property path is not evaluated as expected. I tried it with the more simple query:
PREFIX : <http://ex.org/>
PREFIX da: <http://example.com/data/>
SELECT ?u
WHERE
{ da:Noor ^(:p1|!:p1) ?u }
The algebra looks ok, i.e. the path is reversed:
(project (?u)
(path ?u (alt <http://ex.org/p1> (notoneof <http://ex.org/p1>)) <http://example.com/data/Noor>))
Looks like a bug but I might be wrong indeed. I'll ask on the Jena mailing list and later on post the answer here.
Update:
The problem is with negations when the object itself is grounded - which is the case here due to the reverse operator ^. As per #AndyS' comment, this bug will be fixed in Apache Jena 3.3.0. See JENA-1317

Stardog rule doesn't trigger

I'm having trouble writing a correct Stardog rule. As I haven't found a way to validate the syntax of the rule, I don't now if it's a syntax or a logical error. Eitherway, the rule doesn't seem to be triggered when reasoning is enabled (reasoning=SL in version 2, reasoning=true in version 3).
#prefix : <http://www.example.org/rules#> .
#prefix rule: <tag:stardog:api:rule:> .
#base <http://www.example.org/rules#> .
[] a rule:SPARQLRule ;
rule:content """
PREFIX : <http://www.example.org/rules#>
PREFIX draft: <http://our/prefix#>
IF {
?x a draft:Obs; draft:has_code ?code .
?z a <http://www.w3.org/ns/sparql#UUID> . // OR: BIND (UUID() AS ?z)
}
THEN {
?z a draft:Code .
?x draft:has_code ?z .
}
""" .
I'm trying to trigger the rule with the following SPARQL query:
PREFIX : <http://our/prefix>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?code
FROM <tag:stardog:api:context:default>
FROM <http://our/graph>
WHERE {
?s rdf:type :Obs .
?obs :has_code ?code .
}
This is likely due to the cyclic nature of the rule. You're inferring :has_code which will in turn be used to fire the rule again, and again, and so forth.
This is a bit easier to visualize when you consider how rules with more than one atom in the header a broken up.

add RDFS inference rules support in endpoint SPARQL

I have create an endpoint SPAQL on OpenLink Virtuoso.
All work well, but i have to access on the data in a Container, in particular a rdf:Seq.
I have a Seq like this:
<myrdf:has_stoptimes>
<rdf:Seq rdf:about="http://test.com/343">
<rdf:li>
<myrdf:StopTime rdf:about="http://test.com/StopTime/434">
...
</ns0:StopTime>
</rdf:li>
<rdf:li>
<myrdf:StopTime rdf:about="http://test.com/StopTime/435">
...
</ns0:StopTime>
</rdf:li>
</rdf:Seq>
Now i see that to access data in a container i can use rdfs:member or FILTER (strstarts(str(?prop), str(rdf:_)) how is explained here
But for my project i have to adopt the first solution because i'm working with Silk and i will use the code syntax like ?a/myrdf:has_stoptimes/rdfs:member without use of "complex" filter.
I have tried to follow this guide but querying the endpoint nothing work how i hoped.
So my question is: how can i query ?a/myrdf:has_stoptimes/rdfs:member on a Virtuoso endpoint SPARQL?Which inference rule i have to add in endpoint SPARQL?
Thank you in advance
UPDATE
I have created the following inference rules in Virtuoso:
ttlp (' #prefix rdfs: .
#prefix rdf: .
rdfs:Container rdf:type rdfs:Class ; rdfs:subClassOf rdfs:Resource .
rdfs:ContainerMembershipProperty a rdfs:Class ; rdfs:subClassOf rdf:Property .
rdf:Seq rdf:type rdfs:Class ; rdfs:subClassOf rdfs:Container .
rdfs:member rdf:type rdf:Property ; rdfs:domain rdfs:Resource ; rdfs:range rdfs:Resource .
', '', 'http://localhost:8890/schema/test') ;
Nothing work querying the SPARQL endpoint like:
define input:inference "http://localhost:8890/schema/property_rules1"
SELECT *
FROM
WHERE {?sep a rdf:Seq.
?seq rdfs:member ?p}
After i tried adding the follow line to the ttl file: rdf:_1 rdfs:subPropertyOf rdfs:member . In this way it work but obviously the results are only for the first element of the container. So is very unconvenient add a line for all of rdf:_n, and i think this is only a temporary solution, it is not correct.
I have tried to add an RDF dump on SILK 2.6.1, and on the section SPARQL of the data source if i run the query:
SELECT *
FROM
WHERE {?sep a rdf:Seq.
?seq rdfs:member ?p}
I obtain the correct result, without specify any inference rules. So i think that in this functionality of SILK there is something that i’m missing in my endpoint SPARQL or am i saying nonsense things?
You can't use variables in property paths, so you can't actually do
?x ?a/has_stoptimes/rdfs:member ?y
Instead, you have to use another variable or blank node in between:
?x ?a ?z . ?z has_stoptimes/rdfs:member ?y
?x ?a [ has_stoptimes/rdfs:member ?y ] .

in turtle or RDF can I add a predicate/object on all subjects that match a criteria?

I am doing some experiments with importing triples formulated in the turtle language
within the openrdf-workbench webapp in Tomcat, which has incorporated a SPARQL endpoint.
I wonder if with turtle, or, generally, in RDF / RDFS is it possible to add a certain predicate/object declaration on all (implicit) subjects conditionally to the existence of another predicate/object.
For example, if I have the following triples defined:
foo:a foo:b foo:c
foo:d foo:b foo:c
foo:e foo:b foo:c
foo:f foo:b foo:c
I would like to automatically add the following predicate/subject to all subjects that match predicate=foo:b and object=foo:c:
(implicit subject) foo:g foo:h
in order to automatically produce the following triples:
foo:a foo:g foo:h
foo:d foo:g foo:h
foo:e foo:g foo:h
foo:f foo:g foo:h
Is this possible?
Alternatively: is there any way to define some triples in order to enable SPARQL to find foo:a/d/e/f when queried for subjects that have foo:g foo:h as predicate/object?
Part 1 - Creating additional information
The first part of your question can be solved in one of two ways:
Using Inference
Using SPARQL Update
Inferencing
Inference is a technique whereby you define rules that infer additional triple based on your existing triples. You typically either use a pre-defined set of rules or use your own custom rules. I think Sesame only supports pre-defined rule sets out of the box so you may want to take a look at OWLIM which is an alternative back end that can be used with Sesame and has much more customisable rules AFAIK.
Inferencing can typically be applied in two ways, one where you only store the rules and you compute the additional information every time a rule fires and another where you pre-compute all the additional information and add it to your database. Which you will want to use depends on how you intend to use your system and there are performance trade offs involved. I'm not going into detail because that's really a whole other question - see Forward vs Backward Chaining for some discussion
SPARQL Update
Alternatively if your rules are relatively simple and you are OK with pre-computing the extra information and adding it to your database you can write SPARQL Updates to do this e.g.
PREFIX foo: <http://example.org/foo#>
INSERT
{
?x foo:g foo:h .
}
WHERE
{
?x foo:b foo:c .
}
Part 2 - Querying the Data
I am guessing you are fairly new to SPARQL because from what you've described this sounds trivial to me.
If I wanted to find all subjects which had the predicate foo:g and the object foo:h I would simply write the following:
PREFIX foo: <http://example.org/foo#>
SELECT ?x
WHERE
{
?x foo:g foo:h .
}
You can do this type of inference using OWL with an axiom of the form
p value a &sqsubseteq; q value b
which says that if something has a as a value for property p, then it also has b as a value for property q. As an example, here's an ontology with four individuals (a, b, c, d), two object properties (p, q), and the axiom (p value c &sqsubseteq; q value d).
#prefix : <http://example.org/add-predicate-object#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<http://example.org/add-predicate-object> a owl:Ontology .
:p a owl:ObjectProperty .
:q a owl:ObjectProperty .
[ a owl:Restriction ;
owl:onProperty :p ;
owl:hasValue :c ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty :q ;
owl:hasValue :d ] . ] .
:a a owl:Thing, owl:NamedIndividual ; :p :c .
:b a owl:Thing, owl:NamedIndividual ; :p :c .
:c a owl:Thing, owl:NamedIndividual .
:d a owl:Thing, owl:NamedIndividual .
In Protégé, the axiom looks like this:
You can enable a reasoner and query for instances of q value d and see:
or you can browse to individuals and see the results: