whitefang1993
whitefang1993

Reputation: 1716

SPARQL: Insert query results as RDF LIST

  1. I want to get from graph A results bound to a specific variable lets say ?s.

  2. Next I want to insert those results as an RDF list in graph B.

This is my SPARQL Update:

prefix foo:<http://foo.com/>
insert
{
    graph <http://B.com>
    {
        ?var foo:propA foo:A ;
             foo:propB [ foo:propA foo:A ;
                         foo:propX ( ?s )
                        ] ;
             foo:propC ?o .
    }
}
where
{
    graph <http://A.com>
    {
        ?s ?p ?o.
        BIND(URI(CONCAT("http://example.org/", STRAFTER( STR(?o), "http://someuri.org/"))) as ?var)
    }
}

My problem is that it inserts this data:

<http://example.org/varX> foo:propA foo:A ;
                          foo:propB [ foo:propA foo:A ;
                                      foo:propX ( <http://s1.com> )
                                    ],
                                    [
                                      foo:propA foo:A ;
                                      foo:propX ( <http://s2.com> )
                                    ] ;
                          foo:propC <http://oX.com> .

Instead I want it to insert this:

<http://example.org/varX> foo:propA foo:A ;
                          foo:propB [ foo:propA foo:A ;
                                      foo:propX ( <http://s1.com> <http://s2.com> )
                                    ] ;
                          foo:propC <http://oX.com> .

Can I achieve this result, is it possible?

Basically I want to set the object for the foo:propX predicate, an RDF list containing the elements values bound to variable ?s.

Note: the exact same query executes fine in RDF4J, but strangely causes Blazegraph to throw a

MalformedQueryException: Undefined vocabulary: http://www.w3.org/1999/02/22-rdf-syntax-ns#first

Upvotes: 1

Views: 849

Answers (1)

Jeen Broekstra
Jeen Broekstra

Reputation: 22042

I don't think this is possible using SPARQL only. You'll need to use some of the API functionality to create the RDF collection.

One way to do this is to first construct your graphB as a Model object in memory, and then at the end insert that model in one go. Something along these lines (untested, but this should illustrate the general idea - have a look at the RDF4J documentation and javadoc for more details):

   ValueFactory vf = conn.getValueFactory();

   TupleQuery query = conn.prepareTupleQuery("SELECT ?s ?o ?var WHERE ...");
   List<BindingSet> queryResult = QueryResults.asList(query.evaluate());

   // map values of var to values of S
   Map<Value, List<Value>> varToS = new HashMap<>();
   ... // do something clever with the query result to fill this HashMap 

   // start building our result graph
   Model graphB = new TreeModel()
   ModelBuilder mb = new ModelBuilder(graphB);
   mb.setNamespace("foo", "http://example.org/");
   mb.namedGraph("foo:graphB");

   for(Value var: varToS.keySet()) {
      BNode propBValue = vf.createBNode();
      BNode propXValue = vf.createBNode();

      mb.subject(var)
           .add("foo:propA", "foo:A")
           .add("foo:propB", propBValue)
        .subject(propBValue)
           .add("foo:propA", "foo:A")
           .add("foo:propX", propXValue);
      // add the values of ?s for the given v as a collection
      RDFCollections.asRDF(varToSet.get(var), propXValue, graphB);                
   }

   // insert our created graphB model into the database
   conn.add(graphB);

Upvotes: 1

Related Questions