Difference between revisions of "MembershipInferencing"

From Linked Data Platform
Jump to: navigation, search
(Generalisation: multiple consequences)
(editing the LDPR)
Line 116: Line 116:
 
== editing the LDPR ==
 
== editing the LDPR ==
  
Editing the LDPR has consequences for the membership triples. Eg changing
+
Editing the LDPC has consequences for the membership triples. Eg changing
 
the foaf:primaryTopic in one of the above examples should change the membership triples.
 
the foaf:primaryTopic in one of the above examples should change the membership triples.
 
This is not specified.
 
This is not specified.

Revision as of 18:28, 15 November 2013

There is a major problem with the LDP spec which comes down to confusing logical and causal consequences. Understanding this problem can resolve this Gordian Knot. But it requires escaping from the Status Quo.

1 Introduction

Alexandre Bertails raised the question How to find the members of an LDPC? We can put this more clearly: how does one find the ldp:members of an LDPC?

The current spec seems to presuppose some rule that allow a client to go from the membership properties to the ldp:members of a Container.

These have to be inferences that could be expressed in SPARQL CONSTRUCT something like this

CONSTRUCT {
  ?ldpc ldp:member ?resource .
} WHERE { 
    ?ldpc ldp:membershipSubject ?subject;
            ldp:membershipPredicate ?relation;
            ldp:membershipObject ?memberRelation .

   ?subject ?relation ?object .
 
   GRAPH ?resource {
      ?resource ?memberRelation ?object . 
   }

}

2 Problems

But this raises a number of problems.

2.1 missing function from object to LDPR member

In only some cases is it possible to find the LDPR that contains the ?object. This is when the ?object is for example a relative <#uri> to the document. But when it is not such a URI it is not possible to find the member.

This can be illustrated simply by the following example:

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
    ldp:membershipSubject <#>;
    ldp:membershipPredicate order:contains;
    ldp:membershipObject foaf:primaryTopic.
]]

$ POST http://example.com/shopping/cart/

[[
<> foaf:primaryTopic <urn:isbn:0470396792> .
]]

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate order:contains;
     ldp:membershipObject foaf:primaryTopic.

<#> order:contains <urn:isbn:0470396792>
]]


2.2 Changing the LDPC membership relations

If any of the membership relations changes then the spec does not describe what should happen to the membership triples. They need to all change or else the client won't be able to find the ldp:member.

Consider an LDPC that contained

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate foaf:knows;
     ldp:membershipObject foaf:primaryTopic.

    <#me> foaf:knows <joe#me>
]]

What if somehow the LDPC now changes the order:buys relation to order:wishes relation

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate rel:loves;
     ldp:membershipObject foaf:primaryTopic.

  <#me> foaf:knows <joe#me> .
]]

It will then no longer be possible to deduce the ldp:member using the rules.

One could then suggest to change the membership triples too. If so this needs to be specified clearly.

But if so, then this will change the meaning of what the first client was writing when it POSTed in the container.

2.3 editing the LDPR

Editing the LDPC has consequences for the membership triples. Eg changing the foaf:primaryTopic in one of the above examples should change the membership triples. This is not specified.

2.4 superfluous

When adding a feature to a spec there needs to be good reason to do so. But if one can go from membership triples to ldp:member properties, which is getting to be quite a complex piece of reasoning for the client, then it will be much easier to run the inverse reasoning starting from ldp:member relations + a rule to the membership properties. Why not just make the life easier for the client and have the inverse reasoning take place? But then we might as well leave that to a later spec.

3 Simpler Solutions

3.1 list ldp:member explicitly

3.1.1 Advantages

  • requires no reasoning on simpler clients to find the ldp:members
  • no membership triples for each container required: when they don't exist one just can't infer any membership triples
  • removes an extra binding between the LDPR and the created membership properties ( when someone edits the object in an LDPR that is pointed to by the ldp:membershipObject relation )
  • if one thinks of ldp:membershipXXX triples in terms of reasoning ( as above ) one could still deduce the membership triples with a rule such as the following which could be applied to a graph that only contains ldp:member relations.
CONSTRUCT {
   ?subject ?relation ?object . 
} WHERE { 
    ?ldpc ldp:membershipSubject ?subject;
            ldp:membershipPredicate ?relation;
            ldp:membershipObject ?memberRelation;
            ldp:member ?resource .
 
   GRAPH ?resource {
      ?resource ?memberRelation ?object . 
   }

}

So given a graph such as

 <> ldp:membershipSubject <#i>;
       ldp:membershipPredicate foaf:knows
       ldp:membershipObject foaf:primaryTopic;
       ldp:member <member> .

And given that <member> contained

<> foaf:primaryTopic <#me>.
<#me> a foaf:Person.
     foaf:name "John Doe" .    

One could conclude that

  <#i> foaf:knows <member#me> .

3.1.2 Disadvantages

  • does not allow one to specify the consequences of POSTing to a container ( see next section )
  • requires us to specify the consequences of changing the ldp:membershipXXX relations - what does it mean to do that?
  • the case for the membershipXXX triples is still not clear. If all that is needed is reasoning, why not push that for a later spec?

3.2 list ldp:member explicitly & no ldp:membershipXXX triples

3.2.1 Advantages

  • save us from specifying all these corner cases that we have currently and that need to be added if one is to fix the above issues
  • requires no reasoning on simpler clients to find the ldp:members
  • simpler spec: no membership triples, no membershipXXX triples

3.2.2 Disadvantages

  • does not allow one to specify the consequences of POSTing to a container ( see next section )

3.3 Think in terms of causal consequence instead of logical consequence

If one wishes to keep the membership rules then think of them not as rules to find ldp:members but instead of as rules to help the client know what he is committed to when POSTing, ie in terms of a request for state change as Erik Wilde would put it. ( note: that you can't request something without being in agreement with the consequences of what you request )

So instead of the above rule one would think of the membershipXXX statements as describing the consequences of what one is committed to when POSTing. (Not all consequences, but as with a contract, the consequences the client needs to be aware of). The server still lists all the ldp:members as in the previous solution but when it finds ldp:membershipXXX properties then it knows that on creation the certain relations will appear. This could perhaps be described by a rule such as:

ON POSTING TO ?ldpc 
CREATING ?member
CONSTRUCT {
   ?subject ?relation ?object .
} WHERE { 
   GRAPH ?ldpc {
      ?ldpc ldp:membershipSubject ?subject;
               ldp:membershipPredicate ?relation;
               ldp:membershipObject ?memberRelation .
   }  
   GRAPH ?member {
     ?member ?memberRelation ?object 
   }
}

This way of looking at the situation allows all of the membership triples to be dropped on vanilla servers, because all they say is what consequences follow on LDPR creation. LDPR Creation still always add an ldp:member relation to the created LDPR, so there is no breaking of monotonicity.

Furthermore there is good reason to have such a feature: it is not superfluous. When someone POSTs something to a shopping cart they do bind themselves to some action ( that of buying ). Same when someone POSTs a form to buy an airplane ticket. It makes sense to have similar functionality in LDP. See also "Volunteering for the army" example.

3.3.1 Advantages

  • save us from specifying all these corner cases that we have currently and that need to be added if one is to fix the above issues
  • requires no reasoning on simpler clients to find the ldp:members
  • no membership triples for each container needed ( when they don't exist one knows there is no more consequences other than the creation of an ldp:member )
  • One can change the membershipTriples over the course of a container's lifetime. Consequences of previous POSTs need not affect consequence of future POSTs. ( Just as changing the law does not make previous behavior that might have falled under the law illegal)
  • It seems to be useful thing to have
  • If this is useful, then it is necessary to have it now, and not to put it in later (because otherwise clients developed now, will not know the consequences of their actions in future versions of LDP ( eg: "Volunteering for the army" )

3.3.2 Notes

  • A Client that does not understand the ldp:membershipXXX relations, MUST NOT POST to the container, as this would otherwise bind the user of the client to the statement that is the consequence of the POST.
  • Not all consequences of a POST are important: only those that bind the user when POSTing. That is the one described by the membershipXXX relations. See theVolunteering for the Army post.

3.3.3 Example

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
    ldp:membershipSubject <#>;
    ldp:membershipPredicate order:contains;
    ldp:membershipObject foaf:primaryTopic.
]]

$ POST http://example.com/shopping/cart/

[[
<> foaf:primaryTopic <urn:isbn:0470396792> .
]]

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate order:contains;
     ldp:membershipObject foaf:primaryTopic;
     ldp:member <member1> . // <- notice the member is listed.

<#> order:contains <urn:isbn:0470396792>. // notice the consequence is also written out.
]]

$ PATCH http://example.com/shopping/cart/

[[
DELETE {
 </shopping/cart/> ldp:membershipPredicate order:contains .
}
INSERT { 
 </shopping/cart/> ldp:membershipPredicate order:wishes .
}
]]

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate order:wishes;
     ldp:membershipObject foaf:primaryTopic;
     ldp:member <member1> .

<#> order:contains <urn:isbn:0470396792> . // <- nothing changes here, the result of previous consequences remain. One does not change someone's previous commitments by changing a container.
]]

$ POST http://example.com/shopping/cart/

[[
<> foaf:primaryTopic <urn:isbn:9781907974045> .
]]

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:membershipSubject <#>;
     ldp:membershipPredicate order:wishes;
     ldp:membershipObject foaf:primaryTopic;
     ldp:member <member1>, <member2> .         // <- it is easy to find the members

<#> order:contains <urn:isbn:0470396792> ;    // <- this relation does not
        order:wishes <urn:isbn:9781907974045> . // <- Notice that the relation changes
]]

3.4 Generalisation: multiple consequences

Once one thinks in terms of causal consequence, in terms of the consequence of actions ( especially POSTing ) then one can see that limiting oneself to one state change is somewhat arbitrary. This can be made clear by having a relation to the rule such as ldp:creationConsequence that could be written out like this:

$ GET http://example.com/shopping/cart/

[[
</shopping/cart/> a ldp:Container;
     ldp:creationConsequence [ ldp:subject  <#>;
                               ldp:predicate order:wishes;
                               ldp:objectSelector foaf:primaryTopic],
                             [ ldp:subject <#>;
                               ldp:predicate order:like;
                               ldp:objectSelector foaf:primaryTopic ];
     ldp:member <member1>, <member2> .         // <- it is easy to find the members

<#> order:contains <urn:isbn:0470396792> ;     
    order:wishes <urn:isbn:9781907974045> . 
]]

( this example is not the convincing. Please improve.)

3.4.1 Todo

  • Find a better name for ldp:creationConsequence