3

I have an RDF file and I need to extract some information from it and write it to a file. I understood how it basically works, but I'm stuck with this:

String queryString = "select ?person ?children where { ?person ?hasChildren ?children}";
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
TupleQueryResult result = tupleQuery.evaluate();     
while (result.hasNext()) {
    BindingSet bindingSet = result.next();
    Value p1 = bindingSet.getValue("person");
    Value p2 = bindingSet.getValue("child");
    println(p1 + " has children " + p2 +"");
}
result.close();

The output I get is like this:

http://example.org/people/person1 has children http://example.org/people/child1
http://example.org/people/person1 has children http://example.org/people/child2

I don't see how to list all the persons with their objects in this format:

person1 has children child1 and child2

How can this be done?

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
user2598997
  • 287
  • 1
  • 2
  • 12
  • 1
    This code can't be the one you're actually running; the query binds the variable `?children`, but you're retrieving the value of a variable named `?child`. – Joshua Taylor Aug 28 '13 at 13:20

1 Answers1

3

You may find this answer, which describes SPARQL's group_concat, useful:

In SPARQL, when you have a result set of query solutions, you can group on one or more of the variables, merging solutions that have these variables in common. For instance, consider the data

@prefix : <http://example.org/people/>.

:person1 :hasChild :child1, :child2, :child3 .
:person2 :hasChild :child4, :child5 .
:person3 :hasChild :child6 .

If you run the following query on it

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

select ?person ?child where { 
  ?person :hasChild ?child .
}

you get results like this:

$ arq --data data.n3 --query query.sparql
----------------------
| person   | child   |
======================
| :person3 | :child6 |
| :person2 | :child5 |
| :person2 | :child4 |
| :person1 | :child3 |
| :person1 | :child2 |
| :person1 | :child1 |
----------------------

Iterating through the results as you have in your question would produce the type of output that you're currently getting. What we'd like to do is to actually get results like:

$ arq --data data.n3 --query query.sparql
----------------------------------------
| person   | child                     |
========================================
| :person3 | :child6                   |
| :person2 | :child4, :child5          |
| :person1 | :child1, :child2, :child3 |
----------------------------------------

and that's exactly what group_by lets us do. A query like this:

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

select ?person (group_concat(?child;separator=' and ') as ?children) where { 
  ?person :hasChild ?child .
}
group by ?person

produces (notice that the variable in the result is ?children, not ?child, because we've used group_concat(...) as ?children to create the new variable ?children):

$ arq --data data.n3 --query query.sparql
---------------------------------------------------------------------------------------------------------------------------
| person   | children                                                                                                     |
===========================================================================================================================
| :person3 | "http://example.org/people/child6"                                                                           |
| :person1 | "http://example.org/people/child3 and http://example.org/people/child2 and http://example.org/people/child1" |
| :person2 | "http://example.org/people/child5 and http://example.org/people/child4"                                      |
---------------------------------------------------------------------------------------------------------------------------

If you use a query like this and iterate through the results, printing them as you have, you'll get output like you want. If you do want to strip the leading http://example.org/people/ off from the persons and children, you'll need a bit more string processing. For instance, using STRAFTER to remove the http://example.org/people/ prefix, you can use a query like this:

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

select
 (strafter(str(?personX),"http://example.org/people/") as ?person)
 (group_concat(strafter(str(?child),"http://example.org/people/");separator=' and ') as ?children)
where { 
  ?personX :hasChild ?child .
}
group by ?personX

to get results like:

$ arq --data data.n3 --query query.sparql
----------------------------------------------
| person    | children                       |
==============================================
| "person3" | "child6"                       |
| "person2" | "child5 and child4"            |
| "person1" | "child3 and child2 and child1" |
----------------------------------------------

which, when you do your printing, will give you results like

person3 has children child6
person2 has children child5 and child4
person1 has children child3 and child2 and child1
Community
  • 1
  • 1
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • Enormously awsome. Thank you very much. Do you know if there is an equivalent for group_concat & strafter in Prolog? – user2598997 Aug 28 '13 at 14:02
  • @user2598997 In pure Prolog? Or are you using a Prolog engine to query RDF (e.g., like what Allego provides)? – Joshua Taylor Aug 28 '13 at 14:07
  • You are right, i'm using prolog in allegrograph: (select(?person ?child)(q ?person !ns:childOf ?child )) – user2598997 Aug 28 '13 at 14:15
  • @user2598997 Hm, aside from some very basic use quite some time ago, I don't have much familiarity with AllegroGraph. I'd suspect that it _also_ supports SPARQL queries, but there might be something you can do in its Prolog as well. This is really a different question though, and I'd suggest that you post it as a separate question so that it gets more visibility. You can reference this one if you want to phrase it as "can I do _this_ in AllegroGraph prolog?" – Joshua Taylor Aug 28 '13 at 14:24
  • Yes, it does support SPARQL queries, i will use it for now. Again thank you. – user2598997 Aug 28 '13 at 14:28