If I want to ask for some different properties A and B, in SPARQL,
where there is one unique A, and possibly several B's belonging to each A.
The resulting query that I get is on the form:
A1, B1
A1, B2
A1, B3
A1, B4
A2, B5
How I would want this query result to look, is more of the form:
A1: B1,B2,B3,B4
A2: B5
Is there a way of doing this in SPARQL? What is this called?
The JSON output for SPARQL is documented in SPARQL 1.1 Query Results JSON Format, and specifically section 3.2.2 Encoding RDF Terms describes how the RDF is encoded in the JSON. Note that the JSON output is really just for encoding the results of a SPARQL query, not for creating JSON objects that correspond to a particular object model. Your best bet is probably to take the results you're getting and manipulate them yourself. There are still a few things that might be helpful from the SPARQL side, though.
group_concat
for combining values
That said, maybe the following can help you get something that will work a bit better for you. If you have data like this:
@prefix : <http://example.org/> .
:object :hasA1 :b1, :b2, :b3, :b4 ;
:hasA2 :b5 .
and a query like this:
prefix : <http://example.org/>
select ?subject ?property ?object
where {
values ?property { :hasA1 :hasA2 }
?subject ?property ?object .
}
you'll get results like:
$ arq --data data.n3 --query query.sparql
-------------------------------
| subject | property | object |
===============================
| :object | :hasA1 | :b4 |
| :object | :hasA1 | :b3 |
| :object | :hasA1 | :b2 |
| :object | :hasA1 | :b1 |
| :object | :hasA2 | :b5 |
-------------------------------
You can use group_concat
to combine all the values for hasA1
into a single value with a query like:
prefix : <http://example.org/>
select ?subject ?property (group_concat(?object;separator=',') as ?cobject)
where {
values ?property { :hasA1 :hasA2 }
?subject ?property ?object .
}
group by ?subject ?property
and get results like:
$ arq --data data.n3 --query query.sparql
------------------------------------------------------------------------------------------------------------------
| subject | property | cobject |
==================================================================================================================
| :object | :hasA2 | "http://example.org/b5" |
| :object | :hasA1 | "http://example.org/b4,http://example.org/b3,http://example.org/b2,http://example.org/b1" |
------------------------------------------------------------------------------------------------------------------
If you ask for the results in JSON format, you'll get the following output, which might work for you, depending on what kinds of entities your b1
–b4
are. Specifically, if they're strings, where concatenation makes sense, this could be fine. If they're something else, it's probably not so useful.
$ arq -out JSON --data data.n3 --query query.sparql
{
"head": {
"vars": [ "subject" , "property" , "cobject" ]
} ,
"results": {
"bindings": [
{
"subject": { "type": "uri" , "value": "http://example.org/object" } ,
"property": { "type": "uri" , "value": "http://example.org/hasA2" } ,
"cobject": { "type": "literal" , "value": "http://example.org/b5" }
} ,
{
"subject": { "type": "uri" , "value": "http://example.org/object" } ,
"property": { "type": "uri" , "value": "http://example.org/hasA1" } ,
"cobject": { "type": "literal" , "value": "http://example.org/b4,http://example.org/b3,http://example.org/b2,http://example.org/b1" }
}
]
}
}
group_concat
with construct
There are JSON serializations of RDF out there, and while they may not be supported by SPARQL engines, you could use a construct
query to generate some RDF that is structured more like your desired form, and then use an RDF serialization converter to convert to a JSON format. For instance, Jena's rdfcat
supports RDF/JSON output. Using a construct
query like this:
prefix : <http://example.org/>
construct {
?subject ?property ?cobject
}
where {
select ?subject ?property (group_concat(?object;separator=',') as ?cobject)
where {
values ?property { :hasA1 :hasA2 }
?subject ?property ?object .
}
group by ?subject ?property
}
(See Can we combine CONSTRUCT with aggregates in SPARQL 1.1? on answers.semanticweb.com for an explanation of why there's a nested query in this query.) This generates RDF of the form:
$ arq --out RDF/XML --data data.n3 --query query.sparql
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://example.org/">
<rdf:Description rdf:about="http://example.org/object">
<hasA1>http://example.org/b4,http://example.org/b3,http://example.org/b2,http://example.org/b1</hasA1>
<hasA2>http://example.org/b5</hasA2>
</rdf:Description>
</rdf:RDF>
We can pipe that through rdfcat
to get some RDF/JSON out, which may finally be closer to what you're looking for:
$ arq --out RDF/XML --data data.n3 --query query.sparql | rdfcat -out RDF/JSON /dev/stdin
{
"http://example.org/object" : {
"http://example.org/hasA2" : [ {
"type" : "literal" ,
"value" : "http://example.org/b5"
}
] ,
"http://example.org/hasA1" : [ {
"type" : "literal" ,
"value" : "http://example.org/b4,http://example.org/b3,http://example.org/b2,http://example.org/b1"
}
]
}
}