Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should blank nodes be ignored in member assertion by default? #248

Open
tpluscode opened this issue Oct 23, 2022 · 3 comments
Open

Should blank nodes be ignored in member assertion by default? #248

tpluscode opened this issue Oct 23, 2022 · 3 comments

Comments

@tpluscode
Copy link
Contributor

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.

@alien-mcl
Copy link
Member

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.

@tpluscode
Copy link
Contributor Author

tpluscode commented Nov 3, 2022

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> has rdf:type equal bibo: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

@tpluscode
Copy link
Contributor Author

tpluscode commented Nov 3, 2022

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 )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants