CONSTRUCT into a named graph

8.3k views Asked by At

I am attempting to use a SPARQL Construct query to create a new named graph from an existing one. The database I am querying contains http://graph.com/old as an existing named graph. I am using Jena TDB as the database, accessed through a Jena Fuseki endpoint. The below query gives me an error:

CONSTRUCT
{
    GRAPH <http://graph.com/new> {
        ?s ?p ?o
    }
}

WHERE
{
    GRAPH <http://graph.com/old> {
        ?s ?p ?o
    }
}

If I remove the graph statement from the CONSTRUCT block, the query works perfectly, but I would like to place the triples into a named graph that I specify instead of the default one.

As far as I could find, the SPARQL 1.1 section on CONSTRUCT does not say anything about constructing into named graphs. Is there a way to do this?

2

There are 2 answers

2
Joshua Taylor On BEST ANSWER

Just as SELECT queries are used when you are interested in getting a set of variable bindings back, CONSTRUCT queries are used you are interested in getting a model back. Just as the variables bound in a SELECT result set are not put into any model or persistent set of bindings, neither is the model built by a CONSTRUCT stored anywhere. You want to use SPARQL 1.1 INSERT. The update features are described in 3 SPARQL 1.1 Update Language. Your update request can thus be written as:

INSERT {
  GRAPH <http://graph.com/new> {
    ?s ?p ?o
  }
}
WHERE {
  GRAPH <http://graph.com/old> {
    ?s ?p ?o
  }
}

For this particular case, though, you might be able to use the COPY operation described in 3.2.3 COPY. COPY removes all the data from the target graph first though, so it might not be applicable to your actual case (understanding that the code you provided may be a minimal example, and not necessarily the actual update you're trying to perform). About COPY the standard says:

The COPY operation is a shortcut for inserting all data from an input graph into a destination graph. Data from the input graph is not affected, but data from the destination graph, if any, is removed before insertion.

COPY ( SILENT )? ( ( GRAPH )? IRIref_from | DEFAULT) TO ( ( GRAPH )? IRIref_to | DEFAULT )

is similar in operation to:

DROP SILENT (GRAPH IRIref_to | DEFAULT);
      INSERT { ( GRAPH IRIref_to )? { ?s ?p ?o } } WHERE { ( GRAPH IRIref_from )? { ?s ?p ?o } }

The difference between COPY and the DROP/INSERT combination is that if COPY is used to copy a graph onto itself then no operation will be performed and the data will be left as it was. Using DROP/INSERT in this situation would result in an empty graph.

If the destination graph does not exist, it will be created. By default, the service may return failure if the input graph does not exist. If SILENT is present, the result of the operation will always be success.

If COPY isn't suitable, then ADD may be what you're looking for:

3.2.5 ADD

The ADD operation is a shortcut for inserting all data from an input graph into a destination graph. Data from the input graph is not affected, and initial data from the destination graph, if any, is kept intact.

ADD ( SILENT )? ( ( GRAPH )? IRIref_from | DEFAULT) TO ( ( GRAPH )? IRIref_to | DEFAULT)

is equivalent to:

INSERT { ( GRAPH IRIref_to )? { ?s ?p ?o } } WHERE { ( GRAPH IRIref_from )? { ?s ?p ?o } }

If the destination graph does not exist, it will be created. By default, the service may return failure if the input graph does not exist. If SILENT is present, the result of the operation will always be success.

0
Peter Hinkelmanns On

If you must use CONSTRUCT, you have to add triples to identify the named graph. One way to do this would be rdf reification.

CONSTRUCT {    
    ?s ?p ?o .
    ?statement 
        a rdf:Statement ;
        rdf:subject ?s ;
        rdf:predicate ?p ;
        rdf:object ?o ;
        ex:targetGraph <http://graph.com/new> ;
    .    
}
WHERE {    
    ?s ?p ?o .
    BIND(BNODE() AS ?statement)    
}

The constructed triples could be loaded into an other database and ingested into the target named graph by another INSERT.

INSERT {
    GRAPH ?graph {
        ?s ?p ?o .
    }        
    WHERE {
    {
        SERVICE <your-triple-store-containing-the-construct> {
            ?s ?p ?o .
            ?statement
                a rdf:Statement ;
                rdf:subject ?s ;
                rdf:predicate ?p ;
                rdf:object ?o ;
                ex:targetGraph ?graph .
            .    
        }    
    }
}

Why on earth would you do such things? As I said above, it is not always possible to use INSERT directly. I.e. it is not available in the context of SHACL-Rules.