-->
In this informative note we offer advice to OSLC Technical Committees on modeling links and relationships between OSLC resources.
The Core workgroup's guidance to OSLC domain workgroups is that relationships are uni-directional and in most cases relationships should be modeled as links. We offer two ways to express relationships, a link and an anchor. Let's define those terms and others that we will use in this document:
The RDF data model gives us a number of value-types to express relationships, some more complex than others. We expect that the majority of links will be expressed with the most simple option, URI Reference or as it is known in conversation, a Link. In this simple case, a Link refers to a RDF assertion where the predicate is the URI. It is the subject, predicate, object that represents the relationship. For more complex cases, when a relationship must be annotated with property-values, we use what is called an Anchor, which is a link plus information that annotates or labels that link. Read the sub-sections below for details and examples of Links and Anchors.
Use this when you need a simple link and you do not need to annotate the link with property values. Most relationships should be represented this way.
In RDF terminology, a link is called a URI Reference. In OSLC resource constraints, you express a link as a property with OSLC valueType of Resource as described in [[OSLCCore3]]. The following example shows a property terms:subscribesTo
that you might find inside a customer resource that links to a resource that is "subscribedTo" by the customer.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> </rdf:RDF>The constraints on the terms:subscribesTo property would include
oscl:valueType oslc:Resource
as shown in the example below.
<#dcterms-title> a oslc:Property ; oslc:name "subscribesTo" ; oslc:occurs oslc:Zero-or-many ; oslc:propertyDefinition terms:subscribesTo ; oslc:valueType oslc:Resource.
Relationships in OSLC resources are at their simplest an RDF property whose object is a URI. In some cases within one system, it is necessary to require a closed link, i.e. require the object of a link be of one or more specific resource types. In general, it is better to be open like the web and not place restrictions on the type of resource linked to. The property's purpose and name should clearly reflect the scenarios it is supporting. Since the usage of these relationship properties may exist for a long period of time, specification authors should use great care in determining these.
As resources evolve over time, and they adapt to different situations, different types will be exposed as targets to existing link types. Well behaved clients should gracefully handle resource types they don't expect when exercising links in resources. Specifications should allow links to be open ended (have any type, specifying Range any), and use text in the property description to suggest expected types, without being limiting. For example: “Change request affects a plan item. It is likely that the target resource will be an oslc_cm:ChangeRequest but that is not necessarily the case.” Some implementations may only work well if the link object comes from a set of “known” or “expected” types. The following graceful degradation sequence is suggested for providers when an unexpected type is encountered:
By "place" we mean the resource that contains the link assertion. In most cases, link information should be captured in one place to avoid information redundancy and the associated information maintenance issues.
There are two general sources of information redundancy:
Duplicated triples have the same problem as any redundancy, and should be avoided whenever possible. This redundancy may be required to provide the information independently from different servers, but it must be handled with care to avoid data integrity issues.
There are times when duplicate triples are necessary, and there is a preferred way to use them. For example, a request to GET resource A might respond with triple "A ex:affects B", and a request to GET resource B might also respond with the same "A ex:affects B" triple. If they are on different servers then B's assertion might get out of date. Clients may judge the authority of any RDF statement based on its origin or provenance.Storing the link in one place simplifies updates.
Relationships are expressed as RDF triples and triples do not have property values - only resources have property values. Links are used to express relationships. Many relationships can be represented by a single link, but some relationships need to be annotated with property values. For example, if I am trying to represent the subscriber relationship between a customer and a magazine, I may need to record an expiration date for the relationship. One way to do this is to use an RDF concept known as reification. Reification is a way to make a statement about a statement. See RDF Syntax Specification: Reifying Statements for more information on this concept (reference: RDF Syntax).
Assuming the subscriber scenario, the example below shows how you would use reification to express the annotation.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Cat_Fancy" /> </terms:Customer> <rdf:Statement rdf:about="#n1"> <terms:expirationDate>2010-06-03</terms:expirationDate> <terms:annualPriceUSD>23.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> <rdf:subject rdf:resource="http://example.com/customers/4321"/> <rdf:object rdf:resource="http://example.com/magazines/Field_and_Stream"/> <rdf:predicate rdf:resource="http://example.com/terms/subscribesTo" /> </rdf:Statement> <rdf:Statement rdf:about="#n2"> <terms:expirationDate>2010-01-22</terms:expirationDate> <terms:annualPriceUSD>15.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/mail" /> <rdf:subject rdf:resource="http://example.com/customers/4321"/> <rdf:object rdf:resource="http://example.com/magazines/Cat_Fancy"/> <rdf:predicate rdf:resource="http://example.com/terms/subscribesTo" /> </rdf:Statement> </rdf:RDF>
However, there is a better RDF/XML form, made possible by the rdf:ID attribute. OSLC implementations should prefer this next form because it is easier to read and easier to parse.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:ID="n1" rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:ID="n2" rdf:resource="http://example.com/magazines/Cat_Fancy" /> </terms:Customer> <rdf:Description rdf:about="#n1"> <terms:expirationDate>2010-06-03</terms:expirationDate> <terms:annualPriceUSD>23.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> </rdf:Description> <rdf:Description rdf:about="#n2"> <terms:expirationDate>2010-01-22</terms:expirationDate> <terms:annualPriceUSD>15.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> </rdf:Description> </rdf:RDF>
And here's how to express the same within the JSON format specified by OSLC Core.
Because we already represent valueType Resource as a JSON object,
we can simply add annotating property-values directly into that.
In this case, adding terms:expirationDate
to the terms:subscribesTo
object.
{ "prefixes" : { "terms": "http://example.com/terms/", "oslc": "http://open-services.net/ns/core#", "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#" }, "rdf:about" : "http://example.com/customers/4321", "rdf:type" : { "rdf:resource" : "http://example.com/terms/Customer" }, "terms:subscribesTo" : [{ "rdf:resource" : "http://example.com/magazines/Field_and_Stream", "terms:expirationDate" : "2010-06-03" "terms:annualPriceUSD" : 23.95, "terms:delivery" : { "rdf:resource" : "http://example.com/terms/online" } }, { "rdf:resource" : "http://example.com/magazines/Cat_Fancy", "terms:expirationDate" : "2010-01-22" "terms:annualPriceUSD" : 15.95, "terms:delivery" : { "rdf:resource" : "http://example.com/terms/mail" } }] }
Although the approaches above work to allow anchors to represent links with properties, reification can have entailment and inferencing issues. When there is a need to reify a statement in order to make statements about the stagement (called hearsay), this may be an indication that there is a missing class in the RDF vocabulary. Rather than reifying the statement, the modeler can create a separate class and create specific relationships to that class. That may actually improve the model. The example above could be modeled by introducing a Subscription to capture information about a customer and their magazine subscriptions. This is sometimes called an associative object.
@prefix terms: <http://example.com/terms/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . <http:terms:Subscription> a rdf:Class. <#s1> a terms:Subscription; terms:magazine <http://example.com/magazines/Cat_Fancy> ; terms:subscriber <http://example.com/customers/4321> ; terms:annualPriceUSD "15.95" ; terms:delivery terms:online ; terms:expirationDate "2010-01-22" . <#s2> a terms:Subscription ; terms:magazine <http://example.com/magazines/Field_and_Stream> ; terms:subscriber <http://example.com/customers/4321> ; terms:annualPriceUSD "23.95" ; terms:delivery terms:online ; terms:expirationDate "2010-06-03" .
In this example, the Subscription subject has all the required information including the magazine, subscriber, anual price, etc. There is no need to reify any statements. A simple query will provide the list of magazines a customer subscribes to.
There are also some anti-patterns that clients and servers should avoid.
Blank nodes may be a convenient shorthand to use in examples - especially in Turtle where the [ ... ] syntax makes blank nodes easy to use. However, blank nodes may make queries and updates much harder, since there is no way to reference a specific blank node later. Introducing an explicit resource with its own URI is usually better practice.
Below is an example of a Blog Entry resource with a blank node for an uploaded-file resource.
@prefix dcterms: <http://purl.org/dc/terms/> . @prefix blog: <http://open-services.net/ns/bogus/blog#> . <http://example.com/blogs/entry/5> a blog:BlogEntry ; dcterms:title "New Wink release available" ; blog:attachment [ a blog:UploadedFile ; dcterms:title "wink-0.9.6.jar" ] .
It would be better to represent the uploaded-file resource with an explicit URI. Note that having an explicit URI does not mean the resource has to be sent in a different HTTP request; in this example, we use a hash URI to have the uploaded-file resource returned in the same HTTP request as its parent blog entry resource.
@prefix dcterms: <http://purl.org/dc/terms/> . @prefix blog: <http://open-services.net/ns/bogus/blog#> . <http://example.com/blogs/entry/5> a blog:BlogEntry ; dcterms:title "New Wink release available" ; blog:attachment <#file> . <#file> a blog:UploadedFile ; dcterms:title "wink-0.9.6.jar" .
Feedback should be directed to the OSLC Core Workgroup mailing-list. TBD - put link here.
The following individuals have participated in the creation of this specification and are gratefully acknowledged:
Project Governing Board:
James Amsden, IBM (co-chair)
Andrii Berezovskyi, KTH (co-chair)
Axel Reichwein, Koneksys
Techical Steering Committee:
James Amsden, IBM
Andrii Berezovskyi, KTH
Axel Reichwein, Koneksys
Additional Participants:
Dave Johnson
Arthur Ryman