Blog
Binding Multiple Values
- 28 July, 2022
- By Dave Cassel
- 2 Comments
With MarkLogic’s SPARQL queries, we can bind a value to constrain the query. Using this capability, we can gather information about something of interest. But what if I want to query against multiple values?
Let’s start with some sample data.
'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))
)
After running this in Query Console, I have 10 triples. Now suppose I want to find the objects where the subject is one of target1, target2, or target3? I have a couple choices. With MarkLogic, I can go after one of these values with a simple bind (the second parameter in sem.sparql):
sem.sparql(
`
select ?obj
where {
?target ?pred ?obj
}
`,
{ target: sem.iri("target1") }
)
To be complete in thinking about my options, I could brute-force it and just run multiple SPARQL queries, one for each of my targets. That’s pretty inefficient.
I could also use a FILTER.
sem.sparql(
`
select ?ojbj
where {
?target ?pred ?obj
FILTER (?target IN (<target1>, <target2>, <target3>))
}
`
)
This is effective, but I’ve learned it’s not very efficient (but better than multiple queries). Another option is to bind the values we’re looking for using sem.sparql‘s second parameter:
'use strict';
sem.sparql(
`
select ?obj
where {
?target ?pred ?obj
}`,
{
target: [sem.iri("target1"), sem.iri("target2"), sem.iri("target3")]
}
)
I loaded up my database with 100,000 triples for a quick test (no other data, no other load). Both ran in a matter of milliseconds, but using the bind approach ran in about a quarter of the time that the FILTER approach took.
If you’re looking to run a SPARQL query and you want to use multiple values, binding an array is the preferred way. Interesting to note, however — you can’t do that in a SPARQL update! Stay tuned for the next post where I’ll cover that.
Share this post:
2 replies on “Binding Multiple Values”
Hey Dave,
Thanks for this post, it helped me solve a bindings problem I was having where I was getting the dreaded “BADRDFVAL” deep inside my sparql endpoint. Playing around with your example I found out what was wrong with mine.
For what its worth, I was trying to return the target with the associated data. I had a BIND() that caused the bad rdf value.
I was using ?target as an object, and trying to bind it into the results.
BIND(?target as ?returnVar) # <– fails bad-val
What worked?
select ?trade ?trader ?ts …
?trade a ?tradeType;
xxx:tradeDate ?ts;
xxx:trader ?trader ; # binds up the trader for return
xxx:trader ?target . # member ship in our target’s bindings
This worked and avoided using sem.sparqlValues() which has an ugly syntax imho.
From what I can tell, there is no way to do this sort of thing directly in a SPARQL without having a VALUES statement. So this raises the question: Is ML invoking the SPARQL multiple times, once for each ?target array member creating a union of the results?
Please share any guesses or insights!
Cheers,
Derek
Hi Derek, thanks for posting. I’ve been thinking about your question but I don’t have an answer. I’m wondering whether there’s a trace flag that might give an answer. The semantics.xqy library doesn’t have any
xdmp:tracecalls in it that I can see, nor do the files in the semantics directory. If I can track down an answer I’ll let you know; please do the same!