Consider the following SPARQL update:
INSERT {
?performance
mo:performer ?performer ; # optional
mo:singer ?singer ; # optional
mo:performance_of [
dc:title ?title ; # mandatory
mo:composed_in [ a mo:Composition ;
mo:composer ?composer # optional
]
]
}
WHERE {}
If I do not provide values (e.g. in Jena's ParameterizedSparqlString.setIri() for ?performer, ?singer, or ?composer, this update won't insert statements with the corresponding objects, which is as intended.
But how can I suppress [] a mo:Composition as well if ?composer is missing. Creating it in a second INSERT whose WHERE filters on ISIRI(?composer) doesn't seem to be an option because that INSERT won't know the blank node that has already been created by the first one.
So how can I support this kind of optional parameters in a single SPARQL update? E.g., is there any means for "storing" the blank node between two INSERTs?
The following seems to work, when the caller sets composition to a blank node if and only if it sets ?composer to an IRI.
if (composer != null) {
parameterizedSparqlString.setIri ("composer" , composer);
parameterizedSparqlString.setParam("composition", NodeFactory.createAnon());
}
INSERT {
?performance
mo:performer ?performer ; # optional
mo:singer ?singer ; # optional
mo:performance_of [
dc:title ?title ; # mandatory
mo:composed_in ?composition ] . # optional
?composition a mo:Composition ;
mo:composer ?composer .
}
WHERE {}
Hats off to #Joshua Taylor for the lead.
I'd still prefer a self-contained version that does not require the additional parameter ?composition (i.e. works without making additional demands on the caller), if that's possible at all.
Related
I might have understood something wrong, so bear with me.
I created a repository called 'reasoning' of type OWL2-RL (tried some other types already too).
I created a rule as follows:
prefix sys: <http://www.ontotext.com/owlim/system#>
INSERT DATA {
<_:pets> sys:addRuleset
'''Prefices { ex : <http://www.example.com#> }
Axioms {}
Rules
{
Id: custom
a <ex:hasPet> b
------------------------------------
b <ex:hasOwner> a
}'''
}
I insert some triples as follows:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ex: <http://www.example.com#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
INSERT DATA {
<ex:hasPet> a <owl:ObjectProperty>;
<rdfs:domain> <ex:Human>;
<rdfs:range> <ex:Pet>.
<ex:someHuman> <ex:hasPet> <ex:somePet>.
}
Consequently I set my rule as default as follows :
PREFIX sys: <http://www.ontotext.com/owlim/system#>
INSERT DATA {
_:b sys:defaultRuleset "pets"
}
I expect the following query
PREFIX ex: <http://www.example.com#>
select * where {
<ex:somePet> ?p ?o .
} limit 100
to return the following inferred triple
<ex:somePet> <ex:hasOwner> <ex:someHuman>
but unfortunately no inferred triples are present in the repository.
Could you please help me? Having a working example with the different steps to take will help me get rules to work in my application.
Thanks in advance!
Kind regards
There are multiple issues, first IRIs, within the Prefixes section of the ruleset must be written without angle brackets, e.g. use ex : http://www.example.com# instead ...
also your data and sample query do not make use of the prefix ex but are absolute IRIs, e.g. instead of
INSERT DATA {
<ex:hasPet> a <owl:ObjectProperty>;
<rdfs:domain> <ex:Human>;
<rdfs:range> <ex:Pet>.
<ex:someHuman> <ex:hasPet> <ex:somePet>.
}
rewrite to
INSERT DATA {
ex:hasPet a owl:ObjectProperty;
rdfs:domain ex:Human;
rdfs:range ex:Pet.
ex:someHuman ex:hasPet ex:somePet.
}
I am trying to replace the value of code_type when it is empty and belongs to ifcowl:IfcSite with "INF" via this attempt. I don't know if this is possible.
First, I get the code_type values I need and I use the "values" block to replace the values
However, some values are empty and among these empty values, I have to replace the empty value by "INF" but only for ifcowl = IfcSite
Here is my attempt and thank you in advance for your help :
select ?code_type ?gid ?VALUE1 ?TEST
PREFIX ifcowl: <http://www.buildingsmart-tech.org/ifcOWL/IFC2X3_TC1#>
PREFIX express: <https://w3id.org/express#>
PREFIX blabla: <https://www.blabla.fr/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX iso23386: <https://www.iso.org/standard/iso23386#>
{
?o a ?class .
GRAPH blabla:optimized {
OPTIONAL {?o blabla:SEQ_GUID ?gid}
OPTIONAL {?o blabla:code_type ?code_type}
OPTIONAL {?o blabla:VALUE1 ?VALUE1}
FILTER (?code_type IN
(""^^xsd:string, "ATE_PCO"^^xsd:string, "ATE_SCA"^^xsd:string, "ATE_TNT"^^xsd:string))
}
optional {
values (?code_type ?TEST) {
("" "ZONE" && ?class = ifcowl:IfcSite)
}
}
optional {
values (?code_type ?TYPE) {
("ATE_PCO" "PCO")
("ATE_SCA" "CABLE")
("ATE_TNT" "TNT")
}
values (?code_type ?NOMOS) {
("ATE_PCO" "ABC")
("ATE_SCA" "BDC")
("ATE_TNT" "EDG")
}
}
}
using gas:service or mediawiki:categoryTree services of Wikidata API is it possible somehow to include mediawiki:pages, mediawiki:subcategories and mediawiki:HiddenCategory attributes in query results? I see these attributes in dumps, but have no luck trying to access them programmatically (with SPARQL or some other API)...
You just need to add your conditions e.g for pages add:
?out mediawiki:pages ?pages .
Result
{
"out" : {
"type" : "uri",
"value" : "https://en.wikipedia.org/wiki/Category:Fictional_ducks"
},
"depth" : {
"datatype" : "http://www.w3.org/2001/XMLSchema#int",
"type" : "literal",
"value" : "1"
},
"pages" : {
"datatype" : "http://www.w3.org/2001/XMLSchema#integer",
"type" : "literal",
"value" : "113"
}
They warn that you can't access this through the UI, so you need to encode your query and pass it in the URL:https://query.wikidata.org/bigdata/namespace/categories/sparql?query=&format=json
Full query:
PREFIX gas: <http://www.bigdata.com/rdf/gas#>
prefix mediawiki: <https://www.mediawiki.org/ontology#>
SELECT * WHERE {
SERVICE gas:service {
gas:program gas:gasClass "com.bigdata.rdf.graph.analytics.BFS" .
gas:program gas:linkType mediawiki:isInCategory .
gas:program gas:traversalDirection "Reverse" .
gas:program gas:in <https://en.wikipedia.org/wiki/Category:Ducks>. # one or more times, specifies the initial frontier.
gas:program gas:out ?out . # exactly once - will be bound to the visited vertices.
gas:program gas:out1 ?depth . # exactly once - will be bound to the depth of the visited vertices.
gas:program gas:maxIterations 8 . # optional limit on breadth first expansion.
}
?out mediawiki:pages ?pages .
} ORDER BY ASC(?depth)
I want to get from graph A results bound to a specific variable lets say ?s.
Next I want to insert those results as an RDF list in graph B.
This is my SPARQL Update:
prefix foo:<http://foo.com/>
insert
{
graph <http://B.com>
{
?var foo:propA foo:A ;
foo:propB [ foo:propA foo:A ;
foo:propX ( ?s )
] ;
foo:propC ?o .
}
}
where
{
graph <http://A.com>
{
?s ?p ?o.
BIND(URI(CONCAT("http://example.org/", STRAFTER( STR(?o), "http://someuri.org/"))) as ?var)
}
}
My problem is that it inserts this data:
<http://example.org/varX> foo:propA foo:A ;
foo:propB [ foo:propA foo:A ;
foo:propX ( <http://s1.com> )
],
[
foo:propA foo:A ;
foo:propX ( <http://s2.com> )
] ;
foo:propC <http://oX.com> .
Instead I want it to insert this:
<http://example.org/varX> foo:propA foo:A ;
foo:propB [ foo:propA foo:A ;
foo:propX ( <http://s1.com> <http://s2.com> )
] ;
foo:propC <http://oX.com> .
Can I achieve this result, is it possible?
Basically I want to set the object for the foo:propX predicate, an RDF list containing the elements values bound to variable ?s.
Note: the exact same query executes fine in RDF4J, but strangely causes Blazegraph to throw a
MalformedQueryException: Undefined vocabulary: http://www.w3.org/1999/02/22-rdf-syntax-ns#first
I don't think this is possible using SPARQL only. You'll need to use some of the API functionality to create the RDF collection.
One way to do this is to first construct your graphB as a Model object in memory, and then at the end insert that model in one go. Something along these lines (untested, but this should illustrate the general idea - have a look at the RDF4J documentation and javadoc for more details):
ValueFactory vf = conn.getValueFactory();
TupleQuery query = conn.prepareTupleQuery("SELECT ?s ?o ?var WHERE ...");
List<BindingSet> queryResult = QueryResults.asList(query.evaluate());
// map values of var to values of S
Map<Value, List<Value>> varToS = new HashMap<>();
... // do something clever with the query result to fill this HashMap
// start building our result graph
Model graphB = new TreeModel()
ModelBuilder mb = new ModelBuilder(graphB);
mb.setNamespace("foo", "http://example.org/");
mb.namedGraph("foo:graphB");
for(Value var: varToS.keySet()) {
BNode propBValue = vf.createBNode();
BNode propXValue = vf.createBNode();
mb.subject(var)
.add("foo:propA", "foo:A")
.add("foo:propB", propBValue)
.subject(propBValue)
.add("foo:propA", "foo:A")
.add("foo:propX", propXValue);
// add the values of ?s for the given v as a collection
RDFCollections.asRDF(varToSet.get(var), propXValue, graphB);
}
// insert our created graphB model into the database
conn.add(graphB);
How do I change the query formula based on whether or not a variable is bound?
I am invoking the magic property like this:
WHERE {
VALUES (?subj) {
([my bound positional parameter value goes here...])
}
?subj :myMagicProperty ?result .
}
Inside the magic property, I do a union:
?result a :Rule .
{
?result :someProp ?subj .
}
UNION
{
FILTER NOT EXISTS {
?result :someProp ?anyValue .
}
}
In other words, get me all results where :someProp is this value or :someProp is not defined.
Here is the tricky part. If ?subj is unbound (i.e., I set it as UNDEF in the VALUES block), the above query goes wild and returns everything.
Instead, I want to check if ?subjis unbound. If ?subj is unbound, :myMagicProperty should only return the following results:
FILTER NOT EXISTS {
?result ?someProp ?anyValue .
}
I have experimented with using FILTER and the BOUND function, but I can't figure out how to get the correct behavior. How can I drop one of UNION clauses from my query when ?subj is not bound?
Updates
Revised the first query to add the VALUES block.
Added missing ?result a :Rule . statement.
Corrected ?someProp to :someProp.
First I'd like to confirm what your intent is. I'd like to do that by asking you to respond to the following query that you can run in TopBraid Composer.
SELECT *
WHERE { GRAPH <http://topbraid.org/examples/kennedys> {
VALUES (?property) {(kennedys:firstName) (kennedys:lastName) (UNDEF)}
{
FILTER(BOUND(?property) )
?s ?property ?result .
}
UNION
{
FILTER(!BOUND(?property))
BIND("not sure what you want to do in this case" AS ?result)
}
}
}
The difference in the code above to your code is that I am setting values of your ?someProp in the VALUES statement, whereas you are setting ?subj.
The UNIONed subgraphs are using BOUND and !BOUND as guards.
Before going further with help I'd like to hear from you with a clearer explanation of the query you are wanting to build. Then I can show you the magic property that will be needed.
It's this piece of your initial post I need to understand more:
Here is the tricky part. If ?subj is unbound (i.e., I set it as UNDEF in the VALUES block), the above query goes wild and returns everything.
Instead, I want to check if ?subj is unbound. If ?subj is unbound, myMagicProperty should only return the following results:
FILTER NOT EXISTS {
?result ?someProp ?anyValue .
}*
With ?someProp undefined, as well as ?result and ?anyValue, what were you expecting to come back? Also this subgraph of yours has no assertions that will populate the graph and therefore will return nothing.
Ralph
The trick is, I need to do the UNION using a variable different than the one passed in as an argument. This way, the UNION operation does not cause the unbound parameter to be bound. After the UNION, I can use a FILTER to control the results based on the input parameter.
SELECT ?result
WHERE {
?result a :Rule .
{
SELECT ?rule ?value ?anyValueMatch
WHERE {
{
?rule :someProp ?value .
BIND (false AS ?anyValueMatch) .
}
UNION
{
FILTER NOT EXISTS {
?rule :someProp ?any .
} .
BIND (true AS ?anyValueMatch) .
} .
}
} .
FILTER ((bound(?subj) && (?value = ?subj)) || (?anyValueMatch = true)) .
}
Another way to do this is with COALESCE:
SELECT ?result
WHERE {
?result a :Rule .
OPTIONAL {
?result :someProp ?value .
}
FILTER (COALESCE(?value = ?subj, !bound(?value)))
}
...this avoids the sub-select and simply filters to include only the ?result matches where '?value = ?subj', and if that clause fails the !bound() clause ensures matches that do not have a :someProp property are also included.