1. Introduction
Creating a Linked Data Event Stream (LDES) server involves understanding two specifications, the LDES specification ([ldes-spec]) and the TREE hypermedia specification ([tree-spec]), upon which the LDES specification is built. The goal of this specification is to describe the requirements for a server that hosts a time-based fragmented LDES and provides a mechanism for adding members to an LDES, based on Linked Data Platform concepts.Note: At this moment this document addresses the requirements of a specific use case. Existing implementations of generic LDES servers are LDES Solid Server and VSDS LDESServer4J.
2. LDES
2.1. Example and definition
This guide uses a running example to explain a Linked Data Event Stream and, in the next chapter, the operations the server supports.
The scenario is a scale that measures weights of a person. The readings are sent to an LDES server which keeps track of every reading.
A reading might look like this:
{ "sensor" : "http://example.com/sensors/weightSensor" , "value" : 78.4 , "timestamp" : "2025-01-01T08:00:00Z" , "unit" : "weightInKg" }
Definition: A LDES is a collection representing a stream of unmodifiable objects called members.
Here is an example of a minimal LDES with three weight readings as members:
@prefix sosa: <http://www.w3.org/ns/sosa/> . @prefix ldes: <https://w3id.org/ldes#> . @prefix tree: <https://w3id.org/tree#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix sensors: <http://example.com/sensors/> . @prefix shapes: <http://example.com/shapes/> . @base <http://example.com/weights/> . <#EventStream> a ldes : EventStream ; ldes : timestampPath sosa : resultTime ; tree : shape shapes : memberShape ; tree : member <2025/01/weight1> , <2025/01/weight2> , <2025/02/weight3> . <2025/01/weight1> a sosa : Observation ; sosa : madeBySensor sensors : weightSensor ; sosa : hasSimpleResult "78.4" ^^ xsd : decimal ; sosa : observedProperty: "weightInKg" ; sosa : resultTime "2025-01-01T08:00:00Z" ^^ xsd : dateTime . <2025/01/weight2> a sosa : Observation ; sosa : madeBySensor sensors : weightSensor ; sosa : hasSimpleResult "78.6" ^^ xsd : decimal ; sosa : observedProperty: "weightInKg" ; sosa : resultTime "2025-01-15T08:00:00Z" ^^ xsd : dateTime . <2025/02/weight3> a sosa : Observation ; sosa : madeBySensor sensors : weightSensor ; sosa : hasSimpleResult "78.1" ^^ xsd : decimal ; sosa : observedProperty: "weightInKg" ; sosa : resultTime "2025-02-01T07:15:00Z" ^^ xsd : dateTime .
Example 1 is formatted in Turtle [TURTLE], a compact human-readable serialisation of RDF [RDF-CONCEPTS], a graph-based data model for linked data. The same information could also be formatted in JSON for linking data [JSON-LD]:
{ "@context" : { "@base" : "http://example.com/weights/" "ldes" : "https://w3id.org/ldes#" , "sensor" : { "@id" : "http://www.w3.org/ns/sosa/madeBySensor" , "@type" : "@id" }, "sosa" : "http://www.w3.org/ns/sosa/" , "timestamp" : { "@id" : "http://www.w3.org/ns/sosa/resultTime" , "@type" : "http://www.w3.org/2001/XMLSchema#dateTime" }, "tree" : "https://w3id.org/tree#" , "unit" : "http://www.w3.org/ns/sosa/observedProperty" , "value" : "http://www.w3.org/ns/sosa/hasSimpleResult" , "xsd" : "http://www.w3.org/2001/XMLSchema#" , "sensors" : "http://example.com/sensors/" , "shapes" : "http://example.com/shapes/" }, "@graph" : [ { "@id" : "#EventStream" , "@type" : "ldes:EventStream" , "ldes:timestampPath" : { "@id" : "sosa:resultTime" }, "tree:shape" : { "@id" : "shapes:memberShape" }, "tree:member" : [ { "@id" : "2025/01/weight1" }, { "@id" : "2025/01/weight2" }, { "@id" : "2025/02/weight3" } ] }, { "@id" : "2025/01/weight1" , "@type" : "sosa:Observation" , "sensor" : "sensors:weightSensor" , "value" : 78.4 , "timestamp" : "2025-01-01T08:00:00Z" , "unit" : "weightInKg" }, { "@id" : "2025/01/weight2" , "@type" : "sosa:Observation" , "value" : 78.6 , "sensor" : "sensors:weightSensor" , "timestamp" : "2025-01-15T08:00:00Z" , "unit" : "weightInKg" }, { "@id" : "2025/02/weight3" , "@type" : "sosa:Observation" , "value" : 78.1 , "sensor" : "sensors:weightSensor" , "timestamp" : "2025-02-01T07:15:00Z" , "unit" : "weightInKg" } ] }
The context (@context) maps terms to IRIs [IRI] (necessary for Linked data). The @graph contains the data itself. Thanks to the term mapping in the context, the members of the LDES almost look identical to the original readings in JSON.
Throughout this document Turtle and JSON-LD serialisations will be used.