HydraCG / Specifications

Specifications created by the Hydra W3C Community Group
Other
139 stars 25 forks source link

Discuss how usage of Collections "breaks" relationships #41

Closed lanthaler closed 5 years ago

lanthaler commented 10 years ago

On Mar 18, 2014, at 3:13 PM, Markus Lanthaler wrote:

On Saturday, March 15, 2014 1:03 AM, Gregg Kellogg wrote:

For that matter, if I have a property that I've described as being a hydra:Link, the value of that property is presumably to a resource returning a collection, rather than the resource directly described as being, e.g., a colleague. If you build a graph from following these indirections, it leads to a graph which co-mingles entities of type hydra:Collection and schema:Person, in this example. I've also addressed this by using different properties (schema:colleagues vs schema:colleague), but this is probably controversial.

Yeah, you know my opinion about that :-) IMO, the consumer needs to be able to reliably work with both forms (and cases that the plural instead of the singular form and vice versa). If so, it actually becomes simpler to just have to deal with a single property instead of two.

Here's an example:

 </GreggKellogg> a schema:Person;
   schema:colleagues </GreggKellogg/colleagues>;
   schema:colleague </MarkusLanthaler>, ...
 </GreggKellogg/colleagues> a hydra:Collection;
   hydra:member </MarkusLanthaler>, ...
 </MarkusLanthaler> a schema:Person .

Yeah.. in principle this is quite similar as lists in RDF. They also introduce intermediary nodes which "break" the direct link between the nodes. It might make sense to discuss this in the spec.

Gregg also suggests to also include "some best practices for dealing with the potential confusion"

gkellogg commented 10 years ago

As discussed on the email chain, an alternative would be a BNode with reverse relationship to the collection:

</GreggKellogg> a foaf:Person;
  foaf:knows [is hydra:member of </GreggKellogg/colleagues>]

Alternatively, if we mint a hydra:isMemberOf property as the inverse of hydra:member:

</GreggKellogg> a foaf:Person;
  foaf:knows [hydra:isMemberOf </GreggKellogg/colleagues>]

(JSON-LD and RDFa both have nice support for reversed properties, so creating such a property probably isn't necessary.

This ends up using the BNode as an existential quantifier for any member of the colleagues collection, so doesn't create anything which would be inconsistent. Dereferencing the is member of relation gets a collection (or possibly, paged collection), which doesn't assert that it is, itself, a colleague. After pulling in the collection, and performing RDFS entailment, you'd get the following:

</GreggKellogg> a foaf:Person;
  foaf:knows
    [a foaf:Person; is hydra:member of </GreggKellogg/colleagues>],
    </MarkusLanthaler> .

<MarkusLanthaler> a foaf:Person .

These statements are entirely consistent, and the BNode is rather more easily ignored than a collection IRI. In JSON-LD, it could look like the following:

{
  "@context": {
    "foaf": "http://xmlns.com/foaf/0.1/",
    "hydra": "<http://www.w3.org/ns/hydra/",
    "memberOf": {"@reverse": "hydra:member"}
  },
  "@id" "GreggKellogg",
  "foaf:knows": {"memberOf": "GreggKellogg/colleagues"}
}

It does mean that saying foaf:knows is a hydra:Link isn't sufficient, but saying hydra:isMemberOf is a hydra:Link would be, and wouldn't need to be asserted on any other property for an API to be able to perform reasonable dereferencing.

lanthaler commented 10 years ago

On Wednesday, March 19, 2014 10:44 PM, Gregg Kellogg wrote:

Vering in to N3 syntax (and changing vocabularies), for the moment, an alternative way of referencing a collection could be through a BNode:

</GreggKellogg> a foaf:Person;
  foaf:knows [is hydra:member of </GreggKellogg/colleagues>]

Alternatively, if we mint a hydra:isMemberOf property as the inverse of hydra:member:

a foaf:Person; foaf:knows [hydra:isMemberOf </GreggKellogg/colleagues>]

(JSON-LD and RDFa both have nice support for reversed properties, so creating such a property probably isn't necessary.

This ends up using the BNode as an existential quantifier for any member of the colleagues collection, so doesn't create anything which would be inconsistent. Dereferencing the is member of relation gets a collection (or possibly, paged collection), which doesn't assert that it is, itself, a colleague. After pulling in the collection, and performing RDFS entailment, you'd get the following:

a foaf:Person; foaf:knows [a foaf:Person; is hydra:member of </GreggKellogg/colleagues>], .

a foaf:Person .

Hmm... I think this is a bit too clever and still creates a triple that you don't want.

These statements are entirely consistent, and the BNode is rather more easily ignored than a collection IRI.

This is a case where we should look at LDP [1], as Paul suggested some time ago. LDP allow you to describe a "DirectContainer" (I find the naming quite confusing) as follows:

</GreggKellogg> a foaf:Person ;
    foaf:knows </MarkusLanthaler> .

</GreggKellogg/friends> a ldp:DirectContainer;
    dcterms:title "Gregg's friends";
    ldp:membershipResource </GreggKellogg>;
    ldp:hasMemberRelation foaf:knows;
    ldp:contains </MarkusLanthaler> .

The problem I have with LDP is that it hardcodes the complete interaction model. It's also kind of tricky to "find" such a container. You have to traverse the graph along non-materialized, reverse properties which is not exactly straightforward IMHO.

In JSON-LD, it could look like the following:

{
  "@context": {
    "foaf": "http://xmlns.com/foaf/0.1/",
    "hydra": "<http://www.w3.org/ns/hydra/",
    "memberOf": {"@reverse": "hydra:member"}
  },
  "@id" "GreggKellogg",
  "foaf:knows": {"memberOf": "GreggKellogg/colleagues"}
}

It does mean that saying foaf:knows is a hydra:Link isn't sufficient, but saying hydra:isMemberOf is a hydra:Link would be, and wouldn't need to be asserted on any other property for an API to be able to perform reasonable dereferencing.

While I don't really like the specific blank node solution you are proposing, I find the principle quite interesting. We could avoid the blank node, and thus a triple we don't want, entirely but just including a member of collection directly:

{
  "@context": {
    "foaf": "http://xmlns.com/foaf/0.1/",
    "hydra": "http://www.w3.org/ns/hydra/core",
    "memberOf": { "@reverse": "hydra:member" }
  },
  "@id" "GreggKellogg",
  "foaf:knows": {
    "@id": "MarkusLanthaler,
    "memberOf": "GreggKellogg/colleagues"
  }
}

WDYT?

[1] http://www.w3.org/TR/ldp

Markus Lanthaler @markuslanthaler

lanthaler commented 10 years ago

(Almost) a duplicate of #33

gkellogg commented 10 years ago

For me, resolving this is pretty much my top priority. At this point, I think there are two basic solutions:

1) Use a separate collection property, which has some semantic relationship to the base property, where the range is specifically a collection. For example:

  </gregg> a foaf:Person; :knowsCollection </gregg/knowsCollection> .
  :knowsCollection :collectionPropertyFor foaf:knows .

Then the collection can reference each member and re-assert the relationship

  </gregg/knowsCollection> a hydra:Collection;
    hydra:member </markus> .
  </gregg> foaf:knows </markus> .

2) In a separate email, @lanthaler described an alternate using an intermediate object, such as the following:

  </gregg> a foaf:Person;
    :hasCollectionIndirector [foaf:knows </gregg/knowsCollection>] .

This could then reference the same type of collection I described above. It sort of breaks foaf:knows, except it does so on a blank resource, which could have some catch-all semantic description, and it at least does not mess up the definition of the primary Person resource.

I see many advantages to the 2nd proposal, but would really like to see this more actively discussed.

lanthaler commented 10 years ago

On Monday, May 12, 2014 8:15 PM, Gregg Kellogg wrote:

This topic's been quiet for a while, but for me, resolving this is pretty much my top priority. At this point, I think there are two basic solutions:

1) Use a separate collection property, which has some semantic relationship to the base property, where the range is specifically a collection. For example:

  </gregg> a foaf:Person; :knowsCollection </gregg/knowsCollection> .
  :knowsCollection :collectionPropertyFor foaf:knows .

Interesting.. so you would set the link from knowsCollection to knows and not vice-versa? What about asserting it on a, what we currently call, SupportedProperty?

Then the collection can reference each member and re-assert the relationship

  </gregg/knowsCollection> a hydra:Collection;
    hydra:member </markus> .
  </gregg> foaf:knows </markus> .

2) In a separate email, @lanthaler described an alternate using an intermediate object, such as the following:

  </gregg> a foaf:Person;
    :hasRelationshipIndirector [foaf:knows </gregg/knowsCollection>] .

This could then reference the same type of collection I described above. It sort of breaks foaf:knows, except it does so on a blank resource, which could have somecatch-all semantic description, and it at least does not mess up the definition of the primary Person resource.

I see many advantages to the 2nd proposal, but would really like to see this more actively discussed.

I would also like to hear more opinions on this. I think it has a number of advantages but, as Gregg points out, it is a bit weird from a semantical point of view.

There's also a third option which would be somewhat similar to what LDP does. Namely assert what subject-property pair the collection is managing. Something like

</gregg/knowsCollection> :manages [
   :subject  </gregg/> ;
   :property foaf:knows
] .

The link to the collection can then be done by something very generic such as rdf:seeAlso.

Last but not least, for some vocabularies (most notably Schema.org) simply sticking to the current approach would work as well but introduces an undesired triple unless you remove it when you ingest the data

</GreggKellog> schema:knows </gregg/knowsCollection>

Gregg, at this stage, what would be your preferred approach?

Markus Lanthaler @markuslanthaler

gkellogg commented 10 years ago

On Monday, May 12, 2014 8:15 PM, Gregg Kellogg wrote: This topic's been quiet for a while, but for me, resolving this is pretty much my top priority. At this point, I think there are two basic solutions:

1) Use a separate collection property, which has some semantic relationship to the base property, where the range is specifically a collection. For example:

 </gregg> a foaf:Person; :knowsCollection </gregg/knowsCollection> .
 :knowsCollection :collectionPropertyFor foaf:knows .

Interesting.. so you would set the link from knowsCollection to knows and not vice-versa? What about asserting it on a, what we currently call, SupportedProperty?

I was just illustrating such a possible assertion. In fact, I did create a hydra:collectionProperty to use on a SupportedProperty, but I didn't find this particularly transparent or satisfying. In fact, it's easier to consider foaf:knows to not be a supported property, in this case.

Then the collection can reference each member and re-assert the relationship

 </gregg/knowsCollection> a hydra:Collection;
   hydra:member </markus> .
 </gregg> foaf:knows </markus> .

2) In a separate email, @lanthaler described an alternate using an intermediate object, such as the following:

 </gregg> a foaf:Person;
   :hasRelationshipIndirector [foaf:knows </gregg/knowsCollection>] .

This could then reference the same type of collection I described above. It sort of breaks foaf:knows, except it does so on a blank resource, which could have some catch-all semantic description, and it at least does not mess up the definition of the primary Person resource.

I see many advantages to the 2nd proposal, but would really like to see this more actively discussed.

I would also like to hear more opinions on this. I think it has a number of advantages but, as Gregg points out, it is a bit weird from a semantical point of view.

There's also a third option which would be somewhat similar to what LDP does. Namely assert what subject-property pair the collection is managing. Something like

</gregg/knowsCollection> :manages [
   :subject  </gregg/> ;
   :property foaf:knows
] .

This is also quite close to something Nikas suggested from the VOID vocabulary:

</gregg> a foaf:Person;
  rdfs:seeAlso [
    a void:Linkset;
    void:subjectsTarget </gregg>;
    void:objectsTarget </gregg/friends>;
    void:linkPredicate foaf:knows
  ] .

Although, this does not assert the relationship in the Collection, but in the Linkset. It does have the advantage of being a pattern from a widley-deployed vocabulary for describing datasets.

The link to the collection can then be done by something very generic such as rdf:seeAlso.

In your example, the seeAlso would presumably directly reference the collection, but would need to extract some useful properties of that collection, perhaps like this:

</gregg> a foaf:Person;
  rdfs:seeAlso </gregg/friends> .
</gregg/friends> a hydra:Collection;
  :manages [
    :property foaf:knows;
    :subject </gregg>
  ] .

They really both have the same amount of indirection, but in your case, it's more :subject => :collection => :manages, and in the VOID case, its :subject => :Linkset => :collection, which does seem a little more natural to me.

Last but not least, for some vocabularies (most notably Schema.org) simply sticking to the current approach would work as well but introduces an undesired triple unless you remove it when you ingest the data

</GreggKellog> schema:knows </gregg/knowsCollection>

Well, I've already objected to this pattern, so that would be a no-go for me.

Gregg, at this stage, what would be your preferred approach?

Markus Lanthaler @markuslanthaler

Gregg

akuckartz commented 10 years ago

Any news on this issue? (I also think that it is an important one)

akuckartz commented 10 years ago

Markus documented the state of discussion on this Wiki page: https://www.w3.org/community/hydra/wiki/Avoid_that_collections_%22break%22_relationships

lanthaler commented 10 years ago

Call for consensus: http://lists.w3.org/Archives/Public/public-hydra/2014Jul/0010.html

gkellogg commented 10 years ago

+1

lanthaler commented 10 years ago

Proposed by Gregg: Make it a best practice that a Collection serialization include the hydra:manages block inline, rather than requiring an additional GET

cdchapman commented 10 years ago

:+1: for inlining the hydra:manages block.

lanthaler commented 10 years ago

RESOLVED: Introduce four new properties, namely hydra:collection, hydra:manages, hydra:subject, and hydra:object, to describe collections and associate them to entities. Declare it a best practice to inline the "manages block" in collection representations.

This decision doesn't address issue #42 (paging) and still leaves it open how the "manages block" will be called; I've raised issue #60 for that.

jacoscaz commented 10 years ago

Has this been implemented? Is there a (presumably unstable) spec that includes hydra:collection, hydra:manages, hydra:subject and hydra:object? If not, when will such a spec be published?

lanthaler commented 10 years ago

Jacopo, it has been decided that this is the design that Hydra will use. The spec, however, hasn’t been updated yet (that’s also the reason why this issues is still open).

Btw. you know that there’s a W3C Community Group working on Hydra (http://www.w3.org/community/hydra/), right? I’d like to invite you to join that group if you are interested in this work. The process to join the group is described in detail at http://www.hydra-cg.com/#community