SPIN constraint using CONSTRUCT: where do the CONSTRUCT's triples go? - sparql

I'm using TopBraid Composer Free Edition (5.1.3) to create ontologies including SPIN constraints. I then load the resulting RDF files into RDF4J (2.0.1) and use RDF4J Workbench for testing.
I'm working on SPIN constraints. Here's an example to check for non-negative signal rates that I've added to the CRO2:SignalRate class:
CONSTRUCT {
?this soo:hasConstraintViolation _:b0 .
_:b0 a spin:ConstraintViolation .
_:b0 rdfs:label "Non-Positive SignalRate" .
_:b0 spin:violationRoot ?this .
_:b0 spin:violationPath Nuvio:hasDataValue .
_:b0 spin:violationLevel spin:Warning .
}
WHERE {
?this Nuvio:hasDataValue ?signalRate .
FILTER (?signalRate <= 0.0) .
}
So, I'm testing this constraint in RDF4J workbench using the following SPARQL update query:
PREFIX inst: <http://www.disa.mil/dso/a2i/ontologies/PBSM/Sharing/Instantiations#>
PREFIX Nuvio: <http://cogradio.org/ont/Nuvio.owl#>
PREFIX CRO2: <http://cogradio.org/ont/CRO2.owl#>
INSERT DATA {
inst:aSignalRate_test a CRO2:SignalRate ;
Nuvio:hasDataValue "-10"^^xsd:long .
}
This test instant violates the constraint shown above. If I omit the spin:violationLevel triple and allow this to default to a spin:Error, then I get an error message from the query and the test instance is not asserted, as expected. When executed as shown, the constraint violation is a spin:Warning, so the inst:aSignalRate_test individual is created with data value -10.0. My question is, where do the assertions in the constraint's CONSTRUCT clause go? I believe they're being asserted since the change in the spin:violationLevel impacts behavior. Note that I've tried to tie into the blank node with my own soo:hasConstraintViolation property, but this doesn't work. Are the CONSTRUCT triples asserted in some other context/graph? I'm just using the default/graph for everything.
I'm looking for the expected triples both using RDF4J Workbench's Explore and using SPARQL queries. For example, the following query returns nothing after I assert my errant CRO2:SignalRate:
PREFIX spin: <http://spinrdf.org/spin#>
SELECT DISTINCT *
WHERE {
?s spin:violationRoot ?o .
}
This behavior is consistent between asserting in TopBraid Composer FE and RDF4J Workbench.
My goal is to find and use the diagnostic messages asserted in case of SPIN constraint violations, preferably by using SPARQL queries to find such diagnostics. Seems reasonable. I'm missing something.
Thanks.

The short answer: you can't.
SPIN constraints are intended to detect violations and report them. In RDF4J, that reporting mechanism is the log.
The relevant part of the SPIN spec (http://spinrdf.org/spin.html#spin-constraints) :
[...] if an ASK constraint evaluates to true for one
instance, then the instance violates the condition. Optionally,
CONSTRUCT queries can create instances of a spin:ConstraintViolation
class that provide details on a specific violation.
Note that there is no requirement on the reasoner to do anything with the data that a CONSTRUCT-based constraint produces - it's merely for optional "additional information".
It's perhaps worth seeing if we could add an enhancement to the reasoner to report such triples back in one form or another, but in the current system, only SPIN rules (using DELETE/INSERT etc) modify the database.

So, following #JeenBroekstra comments and my response comment above, I've switched to using constuctors so that the error information remains as visible artifacts. I've created several of my own subproperties of the spin:constructor in order to keep things ordered. I've also specified the execution order of these constructors so that these checks run ahead of other rules that might be tripped up (e.g. by a negative signal rate).
Advantages of this approach:
The error detail artifacts (e.g. spin:violationRoot) remain visible in the triple store. This is very important in my application which involves machine-to-machine.
All the compliance checks are done, so an individual with multiple problems lists all problems as separate hasConstraintViolation properties, not just the first violation to block instantiation.
Disadvantages of this approach:
The errant individual is still instantiated.
This is not standard behavior, so tools geared to look for constraint artifacts in the logs probably won't find them.
Here's a screen shot of an example rule implemented as a subproperty of spin:constructor:

Related

Clearing the internal string cache in rdf4j with sparql

To avoid a possible "XY problem", let me explain my real goal: I am trying to change the capitalization of language tags in an rdf4j repo, using sparql. But although rdf4j stores language tags as written when they were defined, it knows enough to treat them as case-insensitive as the standard dictates. So it treats my attempted edit as a no-op:
Set-up:
INSERT DATA { test:a skos:prefLabel "hello"#EN }
Attempt:
DELETE { test:a skos:prefLabel "hello"#EN }
INSERT { test:a skos:prefLabel "hello"#en }
WHERE
{ test:a skos:prefLabel "hello"#EN }
Result:
This query does nothing. The language tag is still spelled EN.
Interestingly, this also fails if I execute two separate queries:
Query 1:
DELETE DATA { test:a skos:prefLabel "hello"#EN }
Query 2:
INSERT DATA { test:a skos:prefLabel "hello"#en }
Evidently, deleted strings remain in an internal cache and are resurrected, so that my INSERT query resurrects "hello"#EN instead. A restart will clear the cache, but it's not the best UX...
Now, with some older versions of rdf4j I could clear this internal cache with the magic command CLEAR SILENT GRAPH <urn:uri:cache>. But this does not appear to work with rdf4j 2.3.3, which is what we are stuck with at the moment. Is there still a way to clear the string cache without a restart, or to change the capitalization of language tags in any other way?
PS I found this interesting thread about the handling of case in language tags; but it has brought me no closer to a solution.
At first glance this looks like a bug to me, an unintended consequence of a fix we did donkey's years ago for allowing preservation of case in language tags (https://openrdf.atlassian.net/browse/SES-1659).
I'm not sure there are any SPARQL-only workarounds for this, so please feel free to log a bug report/feature request at https://github.com/eclipse/rdf4j/issues.
Having said that, RDF4J does have functionality for normalizing language tags of course. In particular, the RDF parsers can be configured to normalize language tags (see the Rio configuration documentation), and in addition there's a utility method Literals.normalizeLanguageTag which you can use to convert any language tag to a standard canonical form.

Advantages of using container vs no container in sparql

Normal Data Insertion
{
:sub :pred 'o1'.
:sub :pred 'o2'.
:sub :pred 'o3'.
}
Data insertion using container
{
:sub :pred :_b.
:_b rdf:type rdf:Seq.
:_b rdf:_1 'o1'.
:_b rdf:_2 'o2'.
:_b rdf:_3 'o3'.
}
When I used the basic select query, both the above insertion models were returning results in same order(o1, o2, o3).
What are the benefits we get by container approach(rdf:Seq)?
Is rdf:Seq just for representational purpose or does it perform anything under the hood(i.e, preserves insertion ordering) when queried upon?
My Understanding: Even the container insertion model just works the same as the basic normal model when retrieved upon. So even with the container model, insertion order won't be guaranteed while retrieval. I really don't understand the significance of rdf:Seq (docs link)

Ask about inference on Graphdb

my ontology about social network. And we have simple SWRL rules two people(?p1,?p2) workInOrg Org(?org) => colleagueOf(?p1,?p2) and if thier colleague, one people workInOrg => the other person also works in that Org. I also build OWL Axioms but it cant take affect on Graphdb. Another try is that i wrote a custom rule, but Graphdb only allow to choose one Rule (In my case "owrl2-rl") and my custom rule only take affect when combining on this rule OWL2-RL. Is there a way to use combine rules and write rule effienctly?
SHACL validation is good. Does graphdb has OWL constraint validation ??? (ex: domain-range validation ?)
Thanks.
Damyan's comment above provides the answer
One can do this also with OWL2 RL and property chains (see https://www.w3.org/TR/owl2-profiles/#OWL_2_RL in https://www.w3.org/TR/owl2-profiles/#OWL_2_RL). This would not require custom rules, but inference will be a bit slower
This is how it can work:
:worksIn owl:inverseOf :employerOf
:colleagueOf owl:propertyChainAxiom ( :worksIn :employerOf ) .
:worksIn owl:propertyChainAxiom ( :colleagueOf :worksIn ) .

Apache jena ARQ FILTER optimization

I have a reasonable implementation of Jena over MongoDB by providing impls for Graph and DatasetGraph. SPARQL queries are converted into the appropriate query expressions in MongoDB and material, at least on triple-match-by-triple-match basis, is vended in a high performance way. This is not a surprise; indexes do what they're supposed to do. Graph is wrapped with an RDFS reasoner Model and all is fine.
I am interested in now exploring ways to optimize filtering push-down into MongoDB. For example, this SPARQL:
?s a:attested "2017-06-01T00:00:00Z"^^xsd:dateTime .
results in this setup of a MongoDB find expression:
{ "P" : "a:attested", "O" : { "$date" : 1496275200000 } }
And all is good. But this SPARQL:
?s a:attested ?theDate .
FILTER (?theDate = "2017-06-01T00:00:00Z"^^xsd:dateTime)
causes ARQ to pass only the predicate to Graph::find():
{ "P" : "a:attested" }
and a whole lot of things are pulled from the DB and the filtering is done in ARQ itself. The FILTER expression above is obviously not needed for a simple equality but it proves the point.
The TDB documentation says that "... TDB uses the OpExecutor extension point of ARQ." But the link for OpExecutor goes to a To-Do.
Can anyone point at any examples of anything where something can be hooked or otherwise accessed around the time ARQ calls Graph::ExtendedIterator<Triple> find(Triple m)? It is at this point that my implementation jumps in to craft the query, and if I can ask if filters exist, then I can "improve" the restriction on the query. At this time, it is not so important that I deal with stopping the filtering from happening again in ARQ itself.

How to use CONSTRUCT / WHERE in a SPARQL SPIN rule declaration

Summary
Thank you in advance for helping me write a CONSTRUCT/WHERE statement that can be declared as a SPIN Rule in TopBraid Composer Free Edition and used.
I am trying to embed a SPARQL CONSTRUCT/WHERE statement in a spin:rule declaration and then execute it. I am returning zero inferences to Statements 1 or 2 below. I am using Java 7, and Eclipse 4.3., and TopBraid Composer Free Edition. I have been successful running Statement 3 as a SPIN Constructor Declaration in the classes form (Statement 3). I have been successful running Statement 4 in the SPARQL query editor (interpreter) I have cross-posted to the user forum.
Details
Fact 1: I have not been able to run Statement 1 as a SPIN Rule.
----Statement 1---
CONSTRUCT {
?this owl:hasKey ?x .
}
WHERE {
BIND (spif:generateUUID() AS ?x) .
}
Fact 2: I have not been able to run Statement 2 as a SPIN Rule.
----Statement 2----
CONSTRUCT {
?this owl:hasKey ?x .
}
WHERE {
?this rdfs:subClassOf node:entity .
BIND (spif:generateUUID() AS ?x) .
}
--No Error Message--
Fact 3: However I have been successful with Statement 3 in the constructor field of the classes form.
----Statement 3----
CONSTRUCT {
?this owl:hasKey ?x .
}
WHERE {
BIND (spif:generateUUID() AS ?x) .
}
Success: When a new instance is created a new triple indicating a key is created.
Fact 4: I have been successful with Statement 4 in the SPARQL query editor which is analogous.
----Statement 4----
CONSTRUCT {
?s owl:hasKey ?x .
}
WHERE {
?s rdf:type node:word_use
BIND (spif:generateUUID() AS ?x) .
}
Success: When statement is run all current instances get keys.
Fact 5: I do not have any SPARQL Rules libraries checked in the Ontology Profile form.
Fact 6: I have imported the following two libraries.
<http://spinrdf.org/spin> from local file TopBraid/SPIN/spin.ttl.
<http://spinrdf.org/sp> from local file TopBraid/SPIN/sp.ttl
Fact 7: The namespaces in the file are:
Base URI (Location) - http://example.org/
Default Namespace - http://example.org/
But the Base URI keeps getting reset to:
http://www.semanticweb.org/owl/owlapi/turtle
ace_lexicon - http://attempto.ifi.uzh.ch/ace_lexicon#
arc - http://example.org/arc#
arg - http://spinrdf.org/arg#
concept - http://example.org/concept#
node - http://www.example.org/node#
owl - http://www.w3.org/2002/07/owl#
rdf - http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfs - http://www.w3.org/2001/01/rdf-schema#
skos - http://www.w3.org/2004/02/skos/core#
sp - http://spinrdf.org/sp#
spif - http://spinrdf.org/spif#
spin - http://spinrdf.org/spin#
spl - http://spinrdf.org/spl#
word_sense - http://example.org/word_sense#
word_term - http://example.org/word_term#
word_use - http://example.org/word_use#
Fact 8: The class that I am using has the following assertions.
Name - node:unclassified_concept
SubClassOf - node:entity
Fact 9: An instance of the node:unclassified_concept class is described below.
URI - http://example.org/concept#regardless_of1
rdfs:comment - without attention to
rdfs:isDefinedBy - <http://en.wiktionary.org/wiki/regardless_of>
rdfs:label - regardless of
Fact 10: I have been successful using Jena Generic Rules reasoning as well as the OWL_MEM_RULE_INF OntModelSpec, reading/writing, base models, inf models, and ont models.
Context
The context of my problem is the following. I am building and iteratively executing an ontology and rule set using Java and Jena to prove the concept of OWL/RDF representing, considering, and responding to non-trivial type-written English. The sentence I am using is non-trivial (41 words, three clauses, etc.). The current ontology has 1422 assertions when not run against any OWL/RDF rules (transitivity, etc.). I am using TopBraid Composer when possible to complement Jena programming to make sure I am compliant with conventions and standards.
This post outlines the solution to the problem I posted. I was able to come to this solution via a person who responds to their user forum. https://groups.google.com/forum/#!forum/topbraid-users
The CONSTRUCT/WHERE statement (after revision) I wanted to run was:
CONSTRUCT {
?this owl:hasKey ?x .
}
WHERE {
?this rdf:type node:unclassified_concept .
BIND (spif:generateUUID() AS ?x) .
}
However, if I placed this statement in the spin:rule field of the classes form in TBC and pressed the icon for inferencing, I would receive no inferences and much time would be spent churning by the inferencer.
The solution was to create a subproperty of spin:rule that had spin:rulePropertyMaxIterationCount set to 1 (to avoid infinite loops generated by running the built-in function -- in my case spin:generateUUID().)
Then I needed to "pull" or place that new subproperty (which I named "runOnce") into the classes form that I was trying to create a dependent-upon-a-built-in CONSTRUCT/WHERE rule for.
Finally, in the classes form I needed to select add blank row on the new subproperty RunOnce, and then enter my original CONSTRUCT/WHERE statement there.
Then I ran inferencing and the class used the rule.
In short, if you want to embed a rule in a class in TBC, and that rule uses a builtin function, you need to
-Create a subproperty of spin:rule that has rulePropertyMaxIterationCount
set to 1.
-Include this subproperty in the classes form.
-Embed your CONSTRUCT/WHERE statement that uses the built-in within that
subproperty on the classes form by selecting insert blank line and
copying/pasting it in there.
Note the TBC supported SPIN built-in functions is a smaller set than I believe is in the SPIN API documentation. The list of TBC supported built-ins is here in the TBC product.
Help>
Help Contents>
TopBraid Composer>
Application Development Tools>
SPARQL Motion Scripts>
SPARQL Motion Functions Reference
Hope this helps someone.