# Queries and updates against SPARQL endpoints
The SPARQL Protocol (opens new window) defines how the operations specified in the SPARQL query and update specs can be requested by a client from a SPARQL service via HTTP. Such SPARQL protocol operations can be requested with the SPARQL.Client (opens new window) package.
It consists basically of the SPARQL.Client
module which provides dedicated functions for the various forms of SPARQL query and update operations and generic query/3
and update/3
for the query and update operations.
The query functions can be called with a SPARQL.Query
struct or a SPARQL query as a raw string. By default, a SPARQL query string will be parsed into a SPARQL.Query
struct for validation purposes before the string is send via an HTTP request to the SPARQL protocol service endpoint. This parsing step can be omitted by setting :raw_mode
option to true
on the dedicated
functions for the various SPARQL operation forms.
"SELECT * { ?s ?p ?o .}"
|> SPARQL.Client.select("http://example.com/sparql", raw_mode: true)
On the generic SPARQL.Client.query/3
this raw-mode is not supported, since the parsing is needed there to determine the query form which determines which result to expect.
For SPARQL update operations the picture is a little different. The SPARQL.ex package doesn't provide parsing of SPARQL updates (yet), but except for INSERT
and DELETE
updates this isn't actually needed, since all elements of the updates can be provided directly to the respective functions for the update forms, which will generate valid SPARQL updates.
RDF.Graph.new({EX.S, EX.p, EX.O})
|> SPARQL.Client.insert_data("http://example.com/sparql")
You can still provide hand-written update strings to these functions, but due to the lack of SPARQL update parsing the raw-mode is mandatory then. For the INSERT
and DELETE
update forms this the only way to request them for now.
"""
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
INSERT
{ GRAPH <http://example/bookStore2> { ?book ?p ?v } }
WHERE
{ GRAPH <http://example/bookStore>
{ ?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
"""
|> SPARQL.Client.insert("http://example.com/sparql", raw_mode: true)
For a more detailed description, including the various options, see the API documentation (opens new window).
# SPARQL-star support
The SPARQL-star extensions of the JSON and XML result format are also supported via the standard media-types. Some vendors however, have introduced separate media-types for results with the SPARQL-star extension. You'll have to provide the media-type expected by your vendor via the :accept_header
option and enforce the respective default result format via the :result_format
option.
For example, here's how you can receive SPARQL-star results from Ontotext's GraphDB:
SPARQL.Client.query(sparql_star_select_query, endpoint,
accept_header: "application/x-sparqlstar-results+json",
result_format: :json
)
SPARQL.Client.query(sparql_star_construct_query, endpoint,
accept_header: "application/x-turtlestar",
result_format: :turtle
)
# Examples
# SELECT
query
# Places with free wi-fi from Wikidata
"""
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wikibase: <http://wikiba.se/ontology#>
PREFIX bd: <http://www.bigdata.com/rdf#>
SELECT ?item ?itemLabel (SAMPLE(?coord) AS ?coord)
WHERE {
?item wdt:P2848 wd:Q1543615 ; # wi-fi gratis
wdt:P625 ?coord .
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" }
} GROUP BY ?item ?itemLabel
LIMIT 100
"""
|> SPARQL.Client.query("https://query.wikidata.org/bigdata/namespace/wdq/sparql")
SELECT
query results are returned as a SPARQL.Query.Result
struct:
{:ok, %SPARQL.Query.Result{
results: [
%{
"coord" => ~L"Point(23.32527778 42.695)",
"item" => ~I<http://www.wikidata.org/entity/Q5123174>,
"itemLabel" => ~L"City Garden"en
},
%{
"coord" => ~L"Point(24.74138889 42.13444444)",
"item" => ~I<http://www.wikidata.org/entity/Q7205164>,
"itemLabel" => ~L"Plovdiv Central railway station"en
},
%{
"coord" => ~L"Point(27.9122 43.1981)",
"item" => ~I<http://www.wikidata.org/entity/Q7916008>,
"itemLabel" => ~L"Varna railway station"en
},
%{
"coord" => ~L"Point(23.31966111 42.69133056)",
"item" => ~I<http://www.wikidata.org/entity/Q7937209>,
"itemLabel" => ~L"Vitosha Boulevard"en
},
...
],
variables: ["item", "itemLabel", "coord"]
}
}
# ASK
query
"""
PREFIX : <http://dbpedia.org/resource/>
PREFIX dbo: <http://dbpedia.org/ontology/>
ASK {:Sleepers dbo:starring :Kevin_Bacon }
"""
|> SPARQL.Client.query("http://dbpedia.org/sparql")
ASK
query results are also returned as a SPARQL.Query.Result
struct, but with the results
field containing just a boolean result value.
{:ok, %SPARQL.Query.Result{results: true, variables: nil}}
# DESCRIBE
query
"DESCRIBE <http://dbpedia.org/resource/Elixir_(programming_language)>"
|> SPARQL.Client.query("http://dbpedia.org/sparql")
DESCRIBE
query results are returned as an RDF.Graph
respective as an RDF.Dataset
if the format returned by the server supports quads.
{:ok, #RDF.Graph{name: nil
~I<http://dbpedia.org/resource/Elixir_(programming_language)>
~I<http://dbpedia.org/ontology/influenced>
~I<http://dbpedia.org/resource/LFE_(programming_language)>
~I<http://dbpedia.org/ontology/influencedBy>
~I<http://dbpedia.org/resource/Clojure>
~I<http://dbpedia.org/resource/Erlang_(programming_language)>
~I<http://dbpedia.org/resource/LFE_(programming_language)>
~I<http://dbpedia.org/resource/Ruby_(programming_language)>
~I<http://dbpedia.org/ontology/license>
~I<http://dbpedia.org/resource/Apache_License>
~I<http://dbpedia.org/property/creator>
~I<http://dbpedia.org/resource/José_Valim>
~I<http://dbpedia.org/property/platform>
~I<http://dbpedia.org/resource/Erlang_(programming_language)>
~I<http://purl.org/linguistics/gold/hypernym>
~I<http://dbpedia.org/resource/Language>
~I<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
~I<http://dbpedia.org/class/yago/Abstraction100002137>
~I<http://dbpedia.org/class/yago/ArtificialLanguage106894544>
~I<http://dbpedia.org/class/yago/Communication100033020>
~I<http://dbpedia.org/class/yago/Language106282651>
~I<http://dbpedia.org/class/yago/ProgrammingLanguage106898352>
~I<http://dbpedia.org/class/yago/WikicatProgrammingLanguages>
~I<http://dbpedia.org/class/yago/WikicatProgrammingLanguagesCreatedInThe2010s>
~I<http://dbpedia.org/ontology/Language>
~I<http://dbpedia.org/ontology/ProgrammingLanguage>
~I<http://schema.org/Language>
~I<http://www.w3.org/2002/07/owl#Thing>
~I<http://www.wikidata.org/entity/Q315>
~I<http://www.wikidata.org/entity/Q34770>
~I<http://www.wikidata.org/entity/Q9143>
~I<http://xmlns.com/foaf/0.1/homepage>
~I<http://elixir-lang.org>
~I<http://xmlns.com/foaf/0.1/name>
~L"Elixir"en
...
}
}
# CONSTRUCT
query
"""
PREFIX : <http://example.org/>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX dbp: <http://dbpedia.org/property/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT {
:Elixir
:name ?name ;
:homepage ?homepage ;
:license ?license ;
:creator ?creator .
}
WHERE {
<http://dbpedia.org/resource/Elixir_(programming_language)>
foaf:name ?name ;
foaf:homepage ?homepage ;
dbp:creator ?creator ;
dbo:license ?license .
}
"""
|> SPARQL.Client.query("http://dbpedia.org/sparql")
CONSTRUCT
query results are also returned as an RDF.Graph
respective as an RDF.Dataset
if the format returned by the server supports quads.
{:ok, #RDF.Graph{name: nil
~I<http://example.org/Elixir>
~I<http://example.org/creator>
~I<http://dbpedia.org/resource/José_Valim>
~I<http://example.org/homepage>
~I<http://elixir-lang.org>
~I<http://example.org/license>
~I<http://dbpedia.org/resource/Apache_License>
~I<http://example.org/name>
~L"Elixir"en}}
# INSERT
and DELETE
updates
"""
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
INSERT
{ GRAPH <http://example/bookStore2> { ?book ?p ?v } }
WHERE
{ GRAPH <http://example/bookStore>
{ ?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
"""
|> SPARQL.Client.update("http://example.com/sparql", raw_mode: true)
DELETE
updates work similarly.
# INSERT DATA
and DELETE DATA
updates
RDF.Graph.new({EX.S, EX.p, EX.O})
|> SPARQL.Client.insert_data("http://example.com/sparql")
EX.S
|> EX.p(EX.O)
|> SPARQL.Client.delete_data("http://example.com/sparql")
# LOAD
update
SPARQL.Client.load("http://example.com/sparql", from: "http://example.com/Resource")
# CLEAR
update
SPARQL.Client.clear("http://example.com/sparql", graph: EX.Graph)
SPARQL.Client.clear("http://example.com/sparql", graph: :all, silent: true)
# CREATE
graph management operation
SPARQL.Client.create("http://example.com/sparql", graph: EX.Graph)
# DROP
graph management operation
SPARQL.Client.drop("http://example.com/sparql", graph: EX.Graph)
SPARQL.Client.drop("http://example.com/sparql", graph: :named)
# COPY
graph management operation
SPARQL.Client.copy("http://example.com/sparql",
from: "http://example.com/Graph1", to: "http://example.com/Graph2")
SPARQL.Client.copy("http://example.com/sparql",
from: :default, to: EX.Graph, silent: true)
# MOVE
graph management operation
SPARQL.Client.move("http://example.com/sparql",
from: "http://example.com/Graph1", to: "http://example.com/Graph2")
SPARQL.Client.move("http://example.com/sparql",
from: :default, to: EX.Graph, silent: true)
# ADD
graph management operation
SPARQL.Client.add("http://example.com/sparql",
from: "http://example.com/Graph1", to: "http://example.com/Graph2")
SPARQL.Client.add("http://example.com/sparql",
from: :default, to: EX.Graph, silent: true)