Skip to content

Linked Data Fragments

GCHQDeveloper010 edited this page Jun 10, 2026 · 2 revisions

SPARQL endpoints are expensive to run. And generally have low availability.

The other alternative is to serve you triples as flat files, but these can be hard to fit in memory.

Linked Data Fragments provides a specificaiton that aims for the space between these approaches. It is a lightweight protocol that allows you to expose linked data, but for the SPARQL execution to be performed at the client end.

The Linked Data Fragments specification is in draft and is under active development

Resources

How it works

With a SPARQL enpdoint, you send a SPARQL query to a server, this is interpreted, executed and the results sent to you.

With Linked Data Fragments, the SPARQL execution happens in the client (think a library running on your computer). This client takes your query then it requests the data that is needs to meet the requirements of the SPARQL query. This means that more data than is needed by the user is requested from the server, but the request itself is very quick to execute on the server....this reduces the compute load on the server at the expense of additional data transfer.

See it working in LD Explorer

In LD Explorer goto "Sources -> Catalog -> DBPedia (TPF endpoint)"

Practical implementation of a Linked Data Fragment server

W3C specifications can be a bit tricky to read until you are used to them, but essentially you need to do a few things.

  1. Return paged triples (or quads), based on a simple filter that allows the client to specify Subject, Predicate, Object (,Graph)
  2. With the triples, return metadata that allows the client to navigate the results
  3. If no filter is specified return the first page of results with no filter and appropriate metadata

What does a response look like

Your response will need to include various parts...

Any prefixes you use (optional)

@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
@prefix hydra: <http://www.w3.org/ns/hydra/core#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix void:  <http://rdfs.org/ns/void#> .

A named graph that contains the metadata, the name of the graph is server URL + #metadata

<https://theUrl.com/fragmentServer#metadata> {

Within this metatdata graph

  • Subject server URL + #dataset Predicate rdf:type Object hydra:Collection
  • Subject server URL + #dataset Predicate rdf:type Object void:Dataset
  • Subject server URL + #dataset Predicate void:subset Object server URL + query string
  • Subject server URL + #dataset Predicate hydra:search Object blank nodes as below
    • These define how the server expects to recieve its filters in the hydra:template and,
    • How the different parts of this map to the concepts of rdf:Subject, rdf:Predicate and rdf:Object with hydra:mapping
    <https://theUrl.com/fragmentServer#dataset>
            rdf:type      hydra:Collection , void:Dataset;
            void:subset   <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>;
            hydra:search  [ hydra:mapping   [ hydra:property  rdf:object;
                                              hydra:variable  "object"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:predicate;
                                              hydra:variable  "predicate"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:subject;
                                              hydra:variable  "subject"
                                            ];
                            hydra:template  "https://theUrl.com/fragmentServer{?subject,predicate,object}"
                          ] .

  • Subject server URL + #metadata Predicate foaf:primaryTopic Object server URL + query string
    <https://theUrl.com/fragmentServer#metadata>
            foaf:primaryTopic  <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022> .
  • Subject server URL + query string Predicate rdf:type Object hydra:PartialCollectionView
  • Subject server URL + query string Predicate void:subset Object server URL + query string
  • Subject server URL + query string Predicate void:triples Object literal representing total number of triples
  • Subject server URL + query string Predicate void:first Object URL of the first page of results
  • Subject server URL + query string Predicate hydra:itemsPerPage Object literal representing number of triples per page
  • Subject server URL + query string Predicate void:next Object URL of the next page of results (if relevant)
  • Subject server URL + query string Predicate void:previous Object URL of the previous page of results (if relevant)
  • Subject server URL + query string Predicate hydra:totalItems Object literal representing total number of triples
    <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>
            rdf:type            hydra:PartialCollectionView;
            void:subset         <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>;
            void:triples        "1"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:first         <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022&page=1>;
            hydra:itemsPerPage  "2"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:next          <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022&page=2>;
            hydra:totalItems    "1"^^<http://www.w3.org/2001/XMLSchema#long> .

End of the named graph for metadata

}

Actual data triples

<http://example.org/alice>
        foaf:name  "Alice" .

Comunica quirks

Comunica is a knowledge graph querying framework, it is what sits under the LD-Explorer UI.

Comunica makes some performance optimisations that are not quite compliant with the specifications. This means that the order of the triples in the metadata section is important (the order in the examples works). And you need some of the optional components from the spec (again what is in the example works).

Without these, it'll still work, but your metadata triples will get mixed in with your data by the client.

Complete examples

With a query string

@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
@prefix hydra: <http://www.w3.org/ns/hydra/core#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix void:  <http://rdfs.org/ns/void#> .

<https://theUrl.com/fragmentServer#metadata> {
    <https://theUrl.com/fragmentServer#dataset>
            rdf:type      hydra:Collection , void:Dataset;
            void:subset   <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>;
            hydra:search  [ hydra:mapping   [ hydra:property  rdf:object;
                                              hydra:variable  "object"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:predicate;
                                              hydra:variable  "predicate"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:subject;
                                              hydra:variable  "subject"
                                            ];
                            hydra:template  "https://theUrl.com/fragmentServer{?subject,predicate,object}"
                          ] .
    <https://theUrl.com/fragmentServer#metadata>
            foaf:primaryTopic  <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022> .
    
    <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>
            rdf:type            hydra:PartialCollectionView;
            void:subset         <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022>;
            void:triples        "1"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:first         <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022&page=1>;
            hydra:itemsPerPage  "2"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:next          <https://theUrl.com/fragmentServer?predicate=http://xmlns.com/foaf/0.1/name&object=\\u0022Alice\\u0022&page=2>;
            hydra:totalItems    "1"^^<http://www.w3.org/2001/XMLSchema#long> .
    
}
<http://example.org/alice>
        foaf:name  "Alice" .

With no query string

@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
@prefix hydra: <http://www.w3.org/ns/hydra/core#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix void:  <http://rdfs.org/ns/void#> .

<https://theUrl.com/fragmentServer#metadata> {
    <https://theUrl.com/fragmentServer#dataset>
            rdf:type      hydra:Collection , void:Dataset;
            void:subset   <https://theUrl.com/fragmentServer>;
            hydra:search  [ hydra:mapping   [ hydra:property  rdf:object;
                                              hydra:variable  "object"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:predicate;
                                              hydra:variable  "predicate"
                                            ];
                            hydra:mapping   [ hydra:property  rdf:subject;
                                              hydra:variable  "subject"
                                            ];
                            hydra:template  "https://theUrl.com/fragmentServer{?subject,predicate,object}"
                          ] .
    
    <https://theUrl.com/fragmentServer#metadata>
            foaf:primaryTopic  <https://theUrl.com/fragmentServer> .
    <https://theUrl.com/fragmentServer>
            rdf:type            hydra:PartialCollectionView;
            void:subset         <https://theUrl.com/fragmentServer>;
            void:triples        "7"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:first         <https://theUrl.com/fragmentServer?page=1>;
            hydra:itemsPerPage  "2"^^<http://www.w3.org/2001/XMLSchema#long>;
            hydra:next          <https://theUrl.com/fragmentServer?page=2>;
            hydra:totalItems    "7"^^<http://www.w3.org/2001/XMLSchema#long> .
    
}
<http://example.org/alice>
        foaf:knows  <http://example.org/bob>;
        foaf:name   "Alice" .

Clone this wiki locally