Should blank nodes be ignored in member assertion by default?
tpluscode opened this issue · 3 comments
Describe the requirement
I have been working with member assertions lately and I figured that in the current design they do not make sense when their subject/property/object
are blank nodes
Hydra-agnostic example
In my particular example, I wanted to express a collection of languages in which known books are written. In SPARQL I can express this as
SELECT ?language {
?book dcterms:language ?language .
?book a bibo:Book .
}
To turn that into a member assertion, I first got hydra:property dcterm:language
but the hydra:subject
needed to be something that expresses more patterns.
I used SHACL to create a variable for the ?book
in query. My custom implementation converts that into query patterns above
<book-languages>
hydra:memberAssertion
[
hydra:property dcterms:language ;
hydra:subject
[
a sh:NodeShape ;
sh:targetClass bibo:Book ;
] ;
] ;
.
Proposed solutions
There is nothing in the spec that disallows that but I figured that a blank node has potentially undetermined meaning for a generic client or server. I propose that we explicitly state that if the hydra:subject/predicate/object
is a blank node it SHOULD be ignored by a generic client, unless they explicitly know how to support that particular node (such as sh:NodeShape
here).
That is to prevent queries like []dcterms:language ?language .
Further work
I also propose to describe the use of SHACL or OWL in their respective extensions.
I think your approach is an overkill - I believe whole memberAssertion
block should look like this:
<book-languages>
hydra:memberAssertion
[hydra:property dcterms:language],
[
hydra:property rdf:type;
hydra:object bibo:Book
]
.
It should be interpreted as each resource at book-languages has a predicate of dcterms:language and another predicate of rdf:type of which value is bibo:Book. As for having a blank node used as a value of hydra:object
in my example - indeed it might be troublesome for the client to figure it out what's inside. We could add a statetement in the spec that recommends using non-blank resources here.
This is not how this works :)
First of all, we should require that there are always two properties. Otherwise, what do you suppose is the behavior when it only has hydra:property
?
You say
SELECT ?member WHERE {
?member dcterms:language ?foo
}
but why not the reverse?
SELECT ?member WHERE {
?foo dcterms:language ?member
}
This is why in my implementation I require that a member assertion always has two of the hydra:(subject|predicate|object)
properties.
The second member assertion also does not mean how you interpreted it. It reads as
Every member of
<book-languages>
hasrdf:type
equalbibo:Book
SELECT ?member WHERE {
?member rdf:type bibo:Book
}
The assertions are simple. Else, how would a client know to interpret bibo:Book
at face value as opposed to "objects which are instances of bibo:Book
? Not to mention that you reversed its position
We could add a statetement in the spec that recommends using non-blank resources here.
That is exactly what I proposed above: a blank node it SHOULD be ignored by a generic client. Unless they know how to handle them, such as using using SHACL (or OWL) to describe more complex patterns
Here's a potentially more real-life example of what could be achieved when using SHACL for some crazy-ass member assertions.
Imagine you use singleton property style of property attributes (maybe that would be possible in RDF* too but I won't be able to figure that our on the spot). The canonical example is marriage
# Bob married Jane on October 10th 2000
<Bob> ex:married#1 <Jane> .
ex:married#1 rdfs:subPropertyOf ex:married ; schema:date "2000-10-10" .
# Frank married Lucy on May 20th 1995
<Frank> ex:married#2 <Lucy> .
ex:married#2 rdfs:subPropertyOf ex:married ; schema:date "1995-05-20" .
<Bob> a schema:Person .
<Jane> a schema:Person .
<Frank> a schema:Person .
<Lucy> a schema:Person .
ex:married a owl:SymmetricProperty .
Here's a collection of people married before 2000
<married-before-y2k>
a hydra:Collection ;
hydra:memberAssertion [
hydra:object [
a sh:NodeShape ;
sh:targetClass schema:Person ;
] ;
hydra:property [
a sh:NodeShape ;
sh:property [
sh:path schema:date ;
sh:maxExclusive "2000-01-01"^^xsd:date ;
] , [
sh:path rdfs:subPropertyOf ;
sh:hasValue ex:married ;
]
] ;
] ;
.
A hypothetical collection handler would be able to translate these member assertion shapes to a query like
SELECT ?member
WHERE {
?member ?property ?spouse .
# hydra:object assertion
?spouse rdf:type schema:Person .
# hydra:property assertion(s)
?property rdfs:subPropertyOf ex:married ; schema:date ?date .
FILTER ( ?date < "2000-01-01"^^xsd:date )
}