Warning:
This wiki has been archived and is now read-only.

MembershipInferencing

From Linked Data Platform
Jump to: navigation, search

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 these rules:

1.1 Three types of Rules

This page will consider three types of rules:

1.1.1 membership triples => ldp:member

CONSTRUCT {
  ?ldpc ldp:member ?resource . // <- the consequence
} WHERE { 
    ?ldpc ldp:containerResource ?subject;
          ldp:containsRelation ?relation;
          ldp:insertedContentRelation ?memberRelation .

   ?subject ?relation ?object . // <- the membership triples 
 
   GRAPH ?resource {
      ?resource ?memberRelation ?object . 
   }

}

1.1.2 ldp:member => membership triples

CONSTRUCT {
   ?subject ?relation ?object .  //<- the consequence
} WHERE { 
    ?ldpc ldp:containerResource ?subject;
          ldp:containsRelation ?relation;
          ldp:insertedContentRelation ?memberRelation;
          ldp:member ?resource . // <- a membership relation
 
   GRAPH ?resource {
      ?resource ?memberRelation ?object . 
   }

}

1.1.3 Contract/Causal rule

The following it will be suggested at the end is the most interesting way of interpreting what the group meant to put forward:

ON POSTING TO ?ldpc 
CREATING ?member
CONSTRUCT {
   ?subject ?relation ?object .
} WHERE { 
   GRAPH ?ldpc {
      ?ldpc ldp:containerResource ?subject;
            ldp:containsRelation ?relation;
            ldp:insertedContentRelation ?memberRelation .
   }  
   GRAPH ?member {
     ?member ?memberRelation ?object 
   }
}

This rule is meant to be read as being activated by a POST, which creates a resource named ?member, the rest being usual SPARQL CONSTRUCT. That is that this rule is triggered by an action, it is not a logical rule that can be applied over existing triples.

2 Problems

2.1 missing function from object to LDPR member

This problem arises from the "membership triple" => ldp:member rule described above.

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:containerResource <#>;
    ldp:containsRelation order:contains;
    ldp:insertedContentRelation 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:containerResource <#>;
     ldp:containsRelation order:contains;
     ldp:insertedContentRelation foaf:primaryTopic.

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

2.2 Changing the LDPC membership relations

This problem arises from the "membership triple" <=> ldp:member rules described above, but not for the Causal/Contractual rule.

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. The spec does not explain what the consequences of changing this rule is.

2.2.1 ldp:member => membership triples

For example start with the following LDPC and applying the rule from ldp:member to

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

[[
</shopping/cart/> a ldp:Container;
    ldp:containerResource <#i>;
    ldp:containsRelation foaf:knows;
    ldp:insertedContentRelation foaf:primaryTopic;
    ldp:member <member> .
]]

This would give us _the inferred membership triple_

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

If one then changes the ldp:containsRelation to rel:loves then the implied triple would be

 <#i> rel:loves <member#me> .

2.2.2 membership triples => ldp:member

Or starting with the membership triples and applying the to ldp:member

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

[[
</shopping/cart/> a ldp:Container;
    ldp:containerResource <#i>;
    ldp:containsRelation foaf:knows;
    ldp:insertedContentRelation foaf:primaryTopic .

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

This would give us _the inferred membership triple_

 <#i> ldp:member <member> .

If one then changes the ldp:containsRelation to rel:loves then a client may no longer infer any ldp:member relation.

2.3 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.

This reason problem does not apply to the "causal/contractual consequence rule".

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:insertedContentRelation 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:containerResource ?subject;
         ldp:containsRelation ?relation;
         ldp:insertedContentRelation ?memberRelation;
         ldp:member ?resource .
 
   GRAPH ?resource {
      ?resource ?memberRelation ?object . 
   }

}

So given a graph such as

 <> ldp:containerResource <#i>;
       ldp:containsRelation foaf:knows
       ldp:insertedContentRelation 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:containerResource ?subject;
               ldp:containsRelation ?relation;
               ldp:insertedContentRelation ?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 Theoretical Underpinning

Since the LDP spec is about communication acts over HTTP - what does a GET, PUT, POST, etc... mean - the theoretical space to look at this is the Theory of Speech Acts, whose most famous American expositor is John Searle, Professor at Berkeley. His most recent book Making the Social World: The Structure of Human Civilisation" summarises his work over the past 50 years. Most interactions in human civilisation are based on speech acts, that tie the speaker to something: be it the truth of what he says, or to a contract he is signing, or to a promise he made, etc... In the Web these types of actions are tied to POST semantics - which are non-indempotent. They have consequences. This is not new to the W3C. Dan Connolly, one of the founding contributors of the Web, wrote up something on the subject A Model of Authority in the Web.

3.3.2 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.3 Notes

  • A Client that does not understand the ldp:membershipXXX relation objects, 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. See theVolunteering for the Army email.
  • 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.

3.3.4 Example

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

</shopping/cart/> a ldp:Container;
    ldp:containerResource <#>;
    ldp:containsRelation order:contains;
    ldp:insertedContentRelation foaf:primaryTopic.

$ POST http://example.com/shopping/cart/
   201 Location: /shopping/cart/member1

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


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

</shopping/cart/> a ldp:Container;
     ldp:containerResource <#>;
     ldp:containsRelation order:contains;
     ldp:insertedContentRelation 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:containsRelation order:contains .
}
INSERT { 
 </shopping/cart/> ldp:containsRelation order:wishes .
}


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

</shopping/cart/> a ldp:Container;
     ldp:containerResource <#>;
     ldp:containsRelation order:wishes;
     ldp:insertedContentRelation 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:containerResource <#>;
     ldp:containsRelation order:wishes;
     ldp:insertedContentRelation 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