Question

Given a generic graph of objects and directed relations:

@prefix obj: <http://example.org/obj/> .
@prefix rel: <http://example.org/rel/> .

obj:obj1 rel:rel1 obj:obj2 .
obj:obj3 rel:rel2 obj:obj2 .
obj:obj9 rel:rel5 obj:obj8 .
obj:obj1 rel:rel1 obj:obj3 .

and a subset of objects, say obj1, obj2, obj3, how do I extract the subgraph that contains only this subset of objects regardless of the specific relations from the full graph using a simple SPARQL query? The resulting subgraph should be:

obj:obj1 rel:rel1 obj:obj2 .
obj:obj3 rel:rel2 obj:obj2 .
obj:obj1 rel:rel1 obj:obj3 .

my current attempt is to try every possible relations using a bunch of OPTIONAL clauses, which probably isn't the best way to go about it:

SELECT ?r1 ?r2 ?r3 ?r4 ?r5 ?r6 WHERE {
OPTIONAL {obj:obj1 ?r1 obj:obj2} .
OPTIONAL {obj:obj1 ?r2 obj:obj3} .
OPTIONAL {obj:obj2 ?r3 obj:obj3} .
OPTIONAL {obj:obj2 ?r4 obj:obj1} .
OPTIONAL {obj:obj3 ?r5 obj:obj1} .
OPTIONAL {obj:obj3 ?r6 obj:obj2} . }
Was it helpful?

Solution

Given this data (which is essentially yours, except that I've added the .s at the end of the lines so that it's valid Turtle, and I've added a couple of triples so that we'll be able to see whether just having a subject or object not in the special set will keep the triple out of the results):

@prefix obj: <http://example.org/obj/> .
@prefix rel: <http://example.org/rel/> .

obj:obj1 rel:rel1 obj:obj2 .
obj:obj3 rel:rel2 obj:obj2 .
obj:obj1 rel:rel4 obj:obj8 . # additional triple
obj:obj9 rel:rel7 obj:obj2 . # additional triple
obj:obj9 rel:rel5 obj:obj8 .
obj:obj1 rel:rel1 obj:obj3 .

You could use a query like this:

prefix obj: <http://example.org/obj/>

select ?s ?p ?o where { 
  values ?s { obj:obj1 obj:obj2 obj:obj3 }
  values ?o { obj:obj1 obj:obj2 obj:obj3 }
  ?s ?p ?o .
}

to get results like this:

$ sparql --query query.rq --data data.n3
----------------------------------
| s        | p        | o        |
==================================
| obj:obj1 | rel:rel1 | obj:obj3 |
| obj:obj1 | rel:rel1 | obj:obj2 |
| obj:obj3 | rel:rel2 | obj:obj2 |
----------------------------------

The use of values here just says that ?s has to be drawn from a particular set of values, and that ?o has to be drawn from a particular set of values. I don't think there's a way to avoid having to repeat the list of special resources in each location. That is, you'll have to write { obj:obj1 obj:obj2 obj:obj3 } twice, but that's still much easier than enumerating all the possible combinations.

You might also consider using a construct here, rather than select, if what you want back is actually the graph, rather than a set of variable bindings. E.g., with this query:

prefix obj: <http://example.org/obj/>

construct { ?s ?p ?o } where { 
  values ?s { obj:obj1 obj:obj2 obj:obj3 }
  values ?o { obj:obj1 obj:obj2 obj:obj3 }
  ?s ?p ?o .
}

you can get the actual RDF graph back:

$ sparql -out TTL --query query.rq --data data.n3
@prefix obj:   <http://example.org/obj/> .
@prefix rel:   <http://example.org/rel/> .

obj:obj1  rel:rel1  obj:obj3 , obj:obj2 .

obj:obj3  rel:rel2  obj:obj2 .
$ sparql -out N-Triples --query query.rq --data data.n3
<http://example.org/obj/obj1> <http://example.org/rel/rel1> <http://example.org/obj/obj3> .
<http://example.org/obj/obj1> <http://example.org/rel/rel1> <http://example.org/obj/obj2> .
<http://example.org/obj/obj3> <http://example.org/rel/rel2> <http://example.org/obj/obj2> .
$ sparql -out RDF/XML --query query.rq --data data.n3
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:obj="http://example.org/obj/"
    xmlns:rel="http://example.org/rel/">
  <rdf:Description rdf:about="http://example.org/obj/obj1">
    <rel:rel1>
      <rdf:Description rdf:about="http://example.org/obj/obj3">
        <rel:rel2 rdf:resource="http://example.org/obj/obj2"/>
      </rdf:Description>
    </rel:rel1>
    <rel:rel1 rdf:resource="http://example.org/obj/obj2"/>
  </rdf:Description>
</rdf:RDF>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top