Re: implementation of core SHACL (using proposed syntax)

On 04/12/2016 10:40 PM, Holger Knublauch wrote:
> On 13/04/2016 1:11, Peter F. Patel-Schneider wrote:
>> Here are a few examples.   These were generated using a simple test harness
>> that  calls an internal function to generate the query for a shape in a shapes
>> graph, prints the query, and then runs the query against a data graph.
>>
>> Dimitris should be able to provide a few examples of the SPARQL code that his
>> implementation produces as well.  The output may not be too different.
>>
>>
>> ex:t1 a sh:Shape ;
>>   sh:scopeClass ex:tscope1 ;
>>   sh:class ex:tclass1 .
>>
>> PREFIX sh: <http://www.w3.org/ns/shacl#>
>> # SHAPE start <http://ex.com/t1>
>>    SELECT  ?this ?message ?severity
>>           ?subject ?predicate ?object (<http://ex.com/t1> AS ?shape )
>>    WHERE { # SHAPE body
>>    { # FRAGMENT
>>    SELECT  ?this ("Does not have required class ex:tclass1" AS ?message)
>> (<http://www.w3.org/ns/shacl#Violation> AS ?severity) (?this AS ?object)
>>    WHERE {  ?this rdf:type/rdfs:subClassOf* <http://ex.com/tscope1> .
>>            FILTER ( ! EXISTS { ?this rdf:type/rdfs:subClassOf*
>> <http://ex.com/tclass1> } ) } }
>>          } # SHAPE end <http://ex.com/t1>
>>
>>
>> ex:t9 a sh:Shape ;
>>   sh:scopeClass ex:tscope2 ;
>>   sh:equals ( ex:p1 ( ex:p2 ex:p2 ) ).
>>
>> PREFIX sh: <http://www.w3.org/ns/shacl#>
>> # SHAPE start <http://ex.com/t9>
>>    SELECT  ?this ?message ?severity
>>           ?subject ?predicate ?object (<http://ex.com/t9> AS ?shape )
>>    WHERE { # SHAPE body
>>    { # FRAGMENT
>>    SELECT  ?this ("Paths don't have equal values" AS ?message)
>> (<http://www.w3.org/ns/shacl#Violation> AS ?severity) (?this AS ?object)
>>    WHERE {  ?this rdf:type/rdfs:subClassOf* <http://ex.com/tscope2> .
>>            { { ?this <http://ex.com/p1> ?value . MINUS { ?this
>> <http://ex.com/p2>/<http://ex.com/p2> ?value . } } UNION
>>           { ?this <http://ex.com/p2>/<http://ex.com/p2> ?value . MINUS { ?this
>> <http://ex.com/p1> ?value.  } } } } }
>>          } # SHAPE end <http://ex.com/t9>
> 
> So far so good. I am however still awaiting your clarification why sh:equals
> suddenly has a different syntax than the other property constraints.
> 
>>
>>
>> ex:unl a sh:Shape ;
>>    sh:scopeClass ex:unlC ;
>>    sh:propValues ( ex:propunl [ a sh:Shape ; sh:hasValue ex:snli ] ) .
>>
>>
>> PREFIX sh: <http://www.w3.org/ns/shacl#>
>> # SHAPE start <http://ex.com/unl>
>>    SELECT  ?this ?message ?severity
>>           ?subject ?predicate ?object (<http://ex.com/unl> AS ?shape )
>>    WHERE { # SHAPE body
>>    { # newContext
>>    SELECT  ?this ?message ?severity ?subject ?predicate ?object
>>    WHERE {
>>     {SELECT (?childGrandparent AS ?parent) ?this # (?childParent AS ?this)
>>             ?message ?severity ?subject ?predicate ?object
>>       WHERE
>>       {{ SELECT (?grandparent AS ?childGrandparent) (?parent AS ?childParent)
>>                 (?message AS ?childMessage) (?severity as ?childSeverity)
>>                 (?subject AS ?childSubject) (?predicate AS ?childPredicate)
>> ?object
>>          WHERE {     # SHAPE start "ub1bL296C30"
>>    SELECT ?parent ?this ?message ?severity
>>           ?subject ?predicate ?object ("ub1bL296C30" AS ?shape )
>>    WHERE { # SHAPE body
>>    { # hasValue
>>    SELECT ?parent ("Missing required value ex:snli" AS ?message)
>> (<http://www.w3.org/ns/shacl#Violation> AS ?severity)
>>    WHERE { { SELECT (IF(BOUND(?p),?p,"UNKNOWN P") AS ?parent)
>> (IF(BOUND(?gp),?gp,"UNKNOWN GP") AS ?grandparent)
>>     WHERE { { SELECT (IF(BOUND(?this),?this,"UNK T") AS ?p)
>> (IF(BOUND(?parent),?parent,"UNK P") AS ?gp) WHERE { ?this
>> rdf:type/rdfs:subClassOf* <http://ex.com/unlC> . } }
>>     } }
>>            FILTER NOT EXISTS { { ?parent <http://ex.com/propunl> ?this . }
>> FILTER sameTerm(?this,<http://ex.com/snli>) } } }
>>          } # SHAPE end "ub1bL296C30"
>>
>>                } }
>>        BIND( (IF(BOUND(?childSubject), ?childSubject, ?childParent)) AS
>> ?subject )
>>        BIND( (IF(BOUND(?childSubject), ?childPredicate, ex:propunl)) AS
>> ?predicate )
>>        BIND( (IF(BOUND(?childParent), ?childParent, "UNKNOWN")) AS ?this )
>>        BIND( CONCAT("In path ex:propunl ",?childMessage) AS ?message )
>>        BIND( <http://www.w3.org/ns/shacl#Violation> AS ?severity )
>>        } }
>>        ?this rdf:type/rdfs:subClassOf* <http://ex.com/unlC> . # subshape inner
>>        } }
>>          } # SHAPE end <http://ex.com/unl>
> 
> Gosh. This is quite a mouthful. I don't want to imagine how more complex
> patterns look like, such as sh:filterShapes.
> 
> And quite a bit of "magic" happening in the code generator. Looking at your
> source code, I see all kinds of code templates techniques with different
> handling of each core construct. All this complexity would have to be moved
> into the spec if we continue to base it on SPARQL. The current design and
> Proposal 3 are much simpler and more consistent, and use the same approach to
> evaluation each core constraint and all extensions. SHACL can then be defined
> using its own extension mechanism.
> 
> Do you have an example of a user-defined constraint component by any chance?
> How would someone formalize the kind of SPARQL generation without pre-binding?
> 
> This also confirms two limitations of this single-query-transformation
> approach (we had discussed this before):
> - inability to generate nested validation results
> - inability to handle recursion
> The current design uses sh:hasShape which doesn't have these limitations.
> 
> Holger


There is no particular reason that the SPARQL code needs to be in the spec.
It is just the result of an implementation.

The SPARQL code is doing part of the job that would be handled by sh:hasShape.
 In the current design sh:hasShape is doing much more, as it has to handle the
complex process of determining which constraint components to run.

The generated code does not do anything to nest validation results.   That is
an optional part of the current specification and there is no indication how
it could work.  I don't see any reason that a generated-code implementation
cannot be implemented.

It is certainly the case that recursion is not handled, but recursion is not
part of SHACL.

peter

Received on Wednesday, 13 April 2016 09:50:01 UTC