Blog
SPARQL Update with Multiple Targets
- 28 July, 2022
- By Dave Cassel
- No Comments
In my last post, I talked about using the bindings
parameter of MarkLogic’s sem.sparql
function to look for multiple values in a SPARQL query. It turns out that approach doesn’t work for SPARQL Update.
I’ll use the same sample data as my previous post:
'use strict'; declareUpdate(); const sem = require("/MarkLogic/semantics") const myPred = sem.iri("myPredicate"); sem.rdfInsert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .map(num => sem.triple(sem.iri(`target${num}`), myPred, num)) )
Now suppose that I want to delete some of those values. I’ll go after the triples with subjects target1
, target2
, and target3
. Let’s try the same approach that works for queries and bind these values as a parameter to the query:
'use strict'; const myPred = sem.iri("myPredicate"); const targets = [sem.iri("target1"), sem.iri("target2"), sem.iri("target3") ]; sem.sparqlUpdate( ` delete { ?target <myPredicate> ?obj } where { ?target <myPredicate> ?obj } `, { target: targets } )
When I run this, I get an error: XDMP-BADRDFVAL
. Uh oh, a bad RDF value. I expect the where
clause here works the same as a SPARQL query, but ?target
and ?obj
get bound and used in the delete
clause. That clause doesn’t like the array. Alright, how can we do this instead?
I’ve found that using SPARQL’s VALUES
clause works.
'use strict'; const myPred = sem.iri("myPredicate"); const targets = [sem.iri("target1"), sem.iri("target2"), sem.iri("target3") ]; sem.sparqlUpdate( ` delete { ?target <myPredicate> ?obj } where { ?target <myPredicate> ?obj VALUES ?target { ${targets.map(iri => '<' + iri + '>').join(' ')} } } ` )
Let’s take a closer look at that VALUES
line. The SPARQL is wrapped in ` (backtick), so we can do string interpolation. I’m wrapping the individual values in ‘<‘ and ‘>’ so that they’ll be seen as IRIs. What the interpreter will see is this:
delete { ?target <myPredicate> ?obj } where { ?target <myPredicate> ?obj VALUES ?target { <target1> <target2> <target3> } } }
This allows me to hit multiple targets with my delete
in the same request.
There is one thing I don’t like about this approach: when we’re using the binding parameter, the actual query string that we’re passing in remains the same for different calls. MarkLogic can interpret the query, build a plan, and cache it in anticipation of the query being called again (like any parameterized query). With this approach, the query itself changes every time it gets called, so caching doesn’t help us. All the same, it works.
Found a better way? Let me know in the comments!
Share this post:
4V Services works with development teams to boost their knowledge and capabilities. Contact us today to talk about how we can help you succeed!
In my last post, I talked about using the bindings parameter of MarkLogic’s sem.sparql function to look for multiple values in a SPARQL query....