2

Is there a way to ensure the order during the retrieval in sparql?

Say I want to store List<Literals>(order important) as an object

{:subj :pred 'o1'. :subj :pred 'o2'. :subj :pred 'o3'}

How can I insert the above data such that when I perform select ?s ?p ?o where {?s ?p ?o} the order shouldn't change?

Do sparql always preserve the insertion data order when retrieved?

In the above example, I used literals as an example. Is there a way of preserving the order of IRIs as well?

I have seen sparql documentation on RDF.Seq, But I didn't understand exactly how to use that. Please provide some simple insert and select queries for ensuring order or share any relevant resources.

harish chava
  • 302
  • 2
  • 15
  • 1
    if you add `List` - whatever this is - as an object, this is supposed to be a container like `rdf:Seq` or `rdf:List` - but then you have to resolve this container sturcture - made of many triples - in you SPARQL query. `select ?s ?p ?o where {?s ?p ?o}` would just return a single row where some bnode is bound to variable `?o` and represents the container/list. So there is no order between RDF triples given that an RDF dataset is a **set** of RDF triples. – UninformedUser Apr 07 '20 at 15:59
  • If we mentioned a node as type `RDF.Seq` and inserted the node in graph store, Is the type just for representational purpose or does anything specific happens(i.e, order preservation) while retrieving or doing any operations? @UninformedUser – harish chava Apr 08 '20 at 10:38

2 Answers2

3

If you need to preserve order you can represent the list as an RDF Collection. If you have a list of strings, e.g.:

 List<String> objects = Arrays.asList("o1", "o2", "o3");

representing it as an RDF collection would look something like this (in Turtle syntax):

_:node a rdf:List;
       rdf:first "o1" ;
       rdf:rest [ 
          rdf:first "o2";
          rdf:rest [
             rdf:first "o3";
             rdf:rest rdf:nil .
          ]
       ].          

That may look cumbersome, but the RDF4J libraries offer some RDF Collection utilities to make handling this easier from code. To transform your Java list to an RDF Collection, you can do something like this:

// starting node of the RDF collection
Resource head = valueFactory.createBNode();
// convert our list and add it to a newly-created Model
Model collection = RDFCollections.asRDF(objects, head, new LinkedHashModel());

Here, collection is just an RDF model (a set of RDF statements) that you can add to your triplestore like any other RDF data (see the RDF4J docs for some further tips on how to work with collections when storing and retrieving from a repository).

To convert a RDF collection back to a Java list (preserving order):

List<Value> values = RDFCollections.asValues(collection, head, new ArrayList<Value>());

Or if you want them back as a list of string objects again:

List<String> values = new ArrayList<>();
RDFCollections.consumeValues(collection, head, v -> values.add(v.stringValue()));

Edit it is also possible to retrieve such RDF collection items in order using SPARQL 1.1, though it is not straightforward. See Is it possible to get the position of an element in an RDF Collection in SPARQL? for a good solution.

All that being said though, it's probably a good idea to stop and think if you actually need to store things in a fixed order. RDF is by its nature unordered, and while RDF Collection modelling provide a mechanism, it's not efficient to store everything as collections.

In most common cases, the order is not really part of the actual data model, but is a presentation issue. In those cases, you can most of the time use a SPARQL query with an ORDER BY clause instead, to sort the query results.

Jeen Broekstra
  • 20,156
  • 4
  • 43
  • 67
  • you should also mention how to access those RDF collections via SPARQL. That's what the TO was also asking and as we now is sometimes weird - RDF4J might have some custom SPARQL function for it, otherwise one would have to sue SPARQL property paths I think – UninformedUser Apr 08 '20 at 02:48
  • 1
    Good point. Added a link to a question that is specifically about that. – Jeen Broekstra Apr 08 '20 at 07:48
1

The use-case does not seem to fit well with the RDF model. Since RDF describes a graph, order of its edges is not important.

Having this said, one simple solution to your particular use-case might be e.g. using a reified node with two extra RDF properties :order and :value :

RDF:

:subj :pred [:order 1; :value 'o1']. 
:subj :pred [:order 2; :value 'o2']. 
:subj :pred [:order 3; :value 'o3'].

SPARQL:

SELECT ?s ?p ?o {
  ?s ?p [:order ?order; :value ?o]
} ORDER BY ?order
  • If we mentioned a node as type `RDF.Seq` and inserted the node in graph store, Is the type just for representational purpose or does anything specific happens(i.e, order preservation) while retrieving or doing any operations? @Petr Křemen – harish chava Apr 08 '20 at 10:37
  • Marking a node as a RDF sequence only prescribes that the node will have container membership functions. So no special handling AFAIK. – Petr Křemen Jun 04 '20 at 04:00