- From: Holger Knublauch <holger@topquadrant.com>
- Date: Fri, 05 Jun 2015 10:54:34 +1000
- To: RDF Data Shapes Working Group <public-data-shapes-wg@w3.org>
- Message-ID: <5570F34A.1000401@topquadrant.com>
Not sure if it helps, but attached is a simplified graphical workflow
for how this proposal would work.
Holger
On 6/5/2015 9:29, Holger Knublauch wrote:
> On 6/5/2015 8:54, Peter F. Patel-Schneider wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA256
>>
>> There were already separate scopes for individual-based scoping and
>> class-based scoping.
>
> Yes, my proposal is to keep sh:scopeClass and sh:nodeShape as
> syntactic sugar for the frequently needed cases that they cover.
>
>> Do you mean that there should now be a new kind of
>> template for scopes, and new special scopes, all separate from
>> constraints?
>
> Yes, because scopes and shapes are very different concepts. Scopes
> produce focus nodes, while constraints validate given focus nodes.
>
>>
>> Constraints are already available, and can do double duty as scopes.
>> Why
>> not use them for determining the scope of a shape particularly as you
>> then
>> actually do use them for this purpose, but as filters. I don't see
>> what the
>> point is of adding all this extra stuff.
>
> Because they cannot always do double duty, as we had discussed here at
> length. This is due to the way that they are implemented. A constraint
> produces violation instances, but what we need are focus nodes. In
> other words, constraints look for the counter examples, while we would
> need the opposite direction to find all nodes that actually fit.
>
> I am surprised about your feedback, because your own proposal had
> exactly the same concept, in form of sh:sparqlScope. In your own
> example, you use it to return all instance of ex:Person:
>
> [ rdf:type sh:Constraint ;
> sh:severity sh:fatalError ;
> sh:report "SELECT ?person" ;
> sh:sparqlScope "?person rdf:type <http://example.org/Person>" ;
> sh:sparqlShape
> """FILTER NOT EXISTS { ?person ex:offspring ?offspring .
> FILTER NOT EXISTS { ?offspring rdf:type ex:Person . } }"""
> ] .
>
> If this scope were a constraint, then it would be formulated in the
> opposite direction "report an error if this is not an instance of
> ex:Person".
>
> All I have done is generalize your approach to allow sparqlScope to
> also be a template, and I have moved your sh:shapeScope into
> sh:filterShape. This solves the problem with your approach, that some
> constraints simply do not bind ?this. Your work-around was to inject
> some magic to bind ?this with all instances of rdfs:Resource, so but
> even this hack now can have an official solution:
>
> sh:ShapeScope
> a sh:ScopeTemplate
> sh:argument [
> sh:predicate sh:shape ; # becomes ?shape in the query
> sh:valueType sh:Shape ;
> rdfs:comment "The shape that all focus nodes must have"
> ] ;
> sh:sparql """
> SELECT ?this
> WHERE {
> ?this a rdfs:Resource .
> FILTER sh:hasShape(?this, ?shape)
> }
> """ .
>
> And we side-step the question whether ?this should by default be all
> subjects, all nodes, all instances, etc. We just define a generic
> mechanism and let the model do the rest. Anyone can add their own
> scoping template.
>
> As a bonus we don't have to look into complex SPARQL query analysis to
> find out whether a query is binding ?this and similar unnecessary
> complexity that few users will understand.
>
> Hope this makes sense, I can elaborate further.
>
> Holger
>
>
>>
>> peter
>>
>>
>> On 06/03/2015 04:16 PM, Holger Knublauch wrote:
>>> I thought more about the issue of generic scopes and filters and have
>>> come up with a variation of Peter's design. Assuming we define
>>>
>>> - Scope: takes a graph as input and produces bindings for the focus
>>> node
>>> (?this)
>>>
>>> Graph -> focus nodes
>>>
>>> - Constraint: that takes a focus node as input and produces (violation)
>>> results:
>>>
>>> focus nodes -> results
>>>
>>> I think we should make Scopes an explicit concept in SHACL's RDF
>>> vocabulary, similar to how shapes are defined. There would be the
>>> following class hierarchy:
>>>
>>> sh:Scope sh:NativeScope sh:TemplateScope
>>>
>>> And native scopes can have sh:sparql (or a JS body etc). Example
>>>
>>> # Applies to all subjects that have a skos:prefLabel ex:MyShape
>>> sh:scope
>>> [ a sh:NativeScope ; # Optional rdf:type triple sh:sparql """ SELECT
>>> DISTINCT ?this WHERE { ?this skos:prefLabel ?any } """ ] ;
>>> sh:constraint
>>> [ a ex:UniqueLanguageConstraint ; ex:predicate skos:prefLabel ; ] .
>>>
>>> This (common) case above could be turned into a template
>>> sh:PropertyScope:
>>>
>>> ex:MyShape sh:scope [ a sh:PropertyScope ; sh:predicate
>>> skos:prefLabel .
>>> ] ; sh:constraint [ a ex:UniqueLanguageConstraint ; ex:predicate
>>> skos:prefLabel ; ] .
>>>
>>> and we could provide a small collection of frequently needed scopes,
>>> e.g.
>>>
>>> - all nodes in a graph - all subjects - all nodes with any rdf:type
>>> - all
>>> IRI nodes from a given namespace
>>>
>>> Systems that don't speak SPARQL would rely on the hard-coded IRIs from
>>> the core vocabulary, such as sh:PropertyScope.
>>>
>>> We could now also formally define the scope behind sh:scopeClass (and
>>> sh:nodeShape):
>>>
>>> sh:ClassScope a sh:TemplateScope ; sh:argument [ sh:predicate
>>> sh:class ;
>>> # Becomes ?class sh:valueType rdfs:Class ; ] ; sh:sparql """ SELECT
>>> ?this WHERE { ?type rdfs:subClassOf* ?class . ?this a ?type . } """ .
>>>
>>> In addition to these scopes, I suggest we turn sh:scopeShape into
>>> sh:filterShape, and use these filters as pre-conditions that are
>>> evaluated for a given set of focus nodes. The workflow then becomes:
>>>
>>> - sh:scope produces bindings for ?this - sh:filterShape filters out the
>>> values of ?this that do not match the given shape - the actual
>>> constraints are evaluated
>>>
>>> I believe this design provides the flexibility of a generic scoping
>>> mechanism (as suggested in Peter's design) without getting into the
>>> complexity of having to analyze SPARQL syntax or rely on hacks with
>>> rdfs:Resource, while having a user-friendly syntax. The fact that we
>>> separate sh:Scope from sh:Shape means that we can enforce different,
>>> explicit semantics on scopes. For example we could allow a sh:Scope to
>>> encapsulate another SPARQL query that tests whether a given ?this is in
>>> scope, i.e. the inverse direction of the SELECT query, to optimize
>>> performance.
>>>
>>> Thanks, Holger
>>>
>>>
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v2
>>
>> iQEcBAEBCAAGBQJVcNcvAAoJECjN6+QThfjzi28H/3x3+0mmUmrKvEkbxuQ4Vp4a
>> 1E65QIwcZuWhmocT+nHwtPT9Bb0nCMA4D+lsCfwGCp671dhoFmrHAAERe/xDKbSL
>> IJ1vRkstNA0Y+QKS29M2eKtICbO+R8z3ez6xlUNUA7yY0TfE4W1zB2nHh/wzJFyY
>> VM9KHhyQV7ZA+c5hdbai163rGOcFu7Mr54LsUiF2nZ5kAlgtZnJfn45Ewfip+kIO
>> a5zBlyqDY5T+GvgSEvFi1u+V0RjZPVnvApxT/oRbepLOu+EintFttH8IpB4T+HBB
>> yv/kyUGNH4lxNrsYVyAEzYmMi6KIUHuQEiI2VfB4tYRwLJwA7+VsECsRcRtjR/A=
>> =0+/m
>> -----END PGP SIGNATURE-----
>
Attachments
- image/png attachment: SHACL-Validation-Process.png
Received on Friday, 5 June 2015 00:56:57 UTC