I am trying to understand how to do filtering in SPARQL with combined AND and OR conditions.
I try to find all physicists living within Newton's lifetime via the Wikidata Query Service (query.wikidata.org). This is my query:
SELECT ?p1 ?p1Label ?p1t1 ?p1t2 ?p2 ?p2Label ?p2t1 ?p2t2
WHERE {
FILTER (?p1=wd:Q935) . # Newton
?p1 wdt:P569 ?p1t1 . # date of birth
?p1 wdt:P570 ?p1t2 . # date of death
?p2 wdt:P106 wd:Q169470 . # physicist
?p2 wdt:P569 ?p2t1 . # date of birth
?p2 wdt:P570 ?p2t2 . # date of death
{ FILTER (xsd:dateTime(?p2t1) > xsd:dateTime(?p1t1))
. FILTER (xsd:dateTime(?p2t1) < xsd:dateTime(?p1t2)) }
UNION
{ FILTER (xsd:dateTime(?p2t2) > xsd:dateTime(?p1t1))
. FILTER (xsd:dateTime(?p2t2) < xsd:dateTime(?p1t2)) }
UNION
{ FILTER (xsd:dateTime(?p2t1) < xsd:dateTime(?p1t1))
. FILTER (xsd:dateTime(?p2t2) > xsd:dateTime(?p1t2)) } .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
ORDER BY xsd:dateTime(?p2t1)
The query can be processed but does not yield any results.
Each one of the three { FILTER . FILTER } blocks works fine when used without the others.
What am I doing wrong?
{ FILTER (xsd:dateTime(?p2t1) > xsd:dateTime(?p1t1))
. FILTER (xsd:dateTime(?p2t1) < xsd:dateTime(?p1t2)) }
evaluates to empty.
UNION does not "or" them together -- || does that.
Each branch of the UNION is a separate graph pattern.
Related
I am trying to list all entries whose names start with the letter 'R' and are older than 20 but It is not working - Can you please give me a hint ?
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?givenname ?Age ?firstName
WHERE {
?Person foaf:givenname ?firstName
{FILTER (?Age > '20')}
UNION
{FILTER regex(?givename, "^(R)")}
}
To find names that start with "R", you can use STRSTARTS():
FILTER( STRSTARTS(?givename, "R") ) .
To filter based on the age, you first have to add/bind this variable in a triple pattern, e.g.:
?Person ex:yourAgeProperty ?Age .
Your age FILTER compares strings (as you use quotation marks and don’t specify a datatype, which defaults to xsd:string). In case the age is given as xsd:integer in your data, you could use:
FILTER( ?Age > "20"^^xsd:integer ) .
And if both filters need to apply, simply list them one after the other (without {} and without UNION). Or you could combine them:
FILTER( STRSTARTS(?givename, "R") && ?Age > "20"^^xsd:integer ) .
https://query.wikidata.org/
This query allows to get the list of olympians having won one medal or more:
SELECT DISTINCT ?pLabel (?p as ?WD) WHERE
{
{?p p:P1344 ?aw.?aw pq:P166 wd:Q15243387.}
UNION {?p p:P1344 ?aw.?aw pq:P166 wd:Q15889641.}
UNION {?p p:P1344 ?aw.?aw pq:P166 wd:Q15889643.}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
}
ORDER BY ?pLabel
But from that point I cant figure a way to count the number of medals awarded by each participant. Any help would be appreciated.
I am currently working with SPARQL (and TopBraidComposer). I have a query which only brings back matching literals, and then filters out the literals based on not wanting certain categories.
Currently, this query is taking a long time to run, and I think it is my FILTER which is causing the delay. I was wondering if someone would have a better and faster way of filtering out (NOT returning) rows which contain a set of key words (ex. cat1, cat2, cat3).
As of now, I am using;
SELECT ?category
WHERE {
?s1 ?p ?category .
?s2 ?p ?category .
FILTER (str(?category) != "Cat1") .
FILTER (str(?category) != "Cat2") .
FILTER (str(?category) != "Cat3") .
FILTER (str(?category) != "Cat4") .
FILTER (str(?category) != "Cat6") .
FILTER (str(?category) != "Cat8") .
}
It's not clear how much you've trimmed down your example, but the code you presented is doing more work than it needs to.
SELECT ?category
WHERE {
?s1 ?p ?category .
?s2 ?p ?category .
FILTER (str(?category) != "Cat1") .
FILTER (str(?category) != "Cat2") .
FILTER (str(?category) != "Cat3") .
FILTER (str(?category) != "Cat4") .
FILTER (str(?category) != "Cat6") .
FILTER (str(?category) != "Cat8") .
}
Suppose your data has
:a :p "Cat0" .
:b :p "Cat0" .
Then the bindings for ?s1, ?s2, ?p? and ?category can be
?s1 ?s2 ?p ?category
--------------------
:a :a :p "Cat0"
:a :b :p "Cat0"
:b :b :p "Cat0"
:b :a :p "Cat0"
That's four ways to select "Cat0". You said that you want literals, but right now you're hitting every kind of ?category and applying str to it multiple times. You might do this instead:
SELECT DISTINCT ?category
WHERE {
?s ?p ?category .
FILTER( isLiteral(?category) &&
!(str(?category) in ("Cat1", "Cat2", "Cat3",
"Cat4", "Cat6", "Cat8")) )
}
I just started using SPARQL, and I'm trying to create a query that retrieves all information where an id has one of a number of predefined values? I have something like this :
SELECT *
WHERE {
?id ?property ?value .
?value a ?type .
?type rdfs:label ?type_value .
FILTER ( ?id IN (<id1>,<idi>,<idn> ) )
}
The problem I've been running into is the query gets really slow when the list of ids gets increasingly large. I intuitively think there's a better way to write this query, but I'm having trouble figuring out how to create this kind of query. I'm thinking along the lines of something like this:
SELECT *
WHERE {
<id_value> ?property ?value .
?value a ?type .
?type rdfs:label ?type_value .
}
where it retrieves all values only for the multiple ids, eliminating the filtering of results at the end, but I can't figure out how to write the query so that it returns all values for an id_value. when I add another line for another id_value, it filters out other values I'm expecting, so I think I'm writing it incorrectly. How can I do this?
Using values, you can write:
SELECT * WHERE {
values ?id { <id1> <idi> <idn> }
?id ?property ?value .
?value a ?type .
?type rdfs:label ?type_value .
}
The SPARQL 1.1 says about values:
Data can be directly written in a graph pattern or added to a query
using VALUES. VALUES provides inline data as a solution sequence which
are combined with the results of query evaluation by a join operation.
It can be used by an application to provide specific requirements on
query results and also by SPARQL query engine implementations that
provide federated query through the SERVICE keyword to send a more
constrained query to a remote query service.
One of the examples is actually very close to what you've already got:
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX : <http://example.org/book/>
PREFIX ns: <http://example.org/ns#>
SELECT ?book ?title ?price
{
VALUES ?book { :book1 :book3 }
?book dc:title ?title ;
ns:price ?price .
}
Try using the VALUES clause instead like so:
SELECT *
WHERE {
VALUES ?id { ...list of ids... }
?id ?property ?value .
?value a ?type .
?type rdfs:label ?type_value .
}
This should hopefully be much more efficient that using the FILTER approach.
I would like to write a single SPARQL query to find the k nearest neighbors for a set of vectors. To find the average label for the 100 nearest neighbors for a single vector I can use the following query:
PREFIX : <ml://>
PREFIX vector: <ml://vector/>
PREFIX feature: <ml://feature/>
SELECT (AVG(?label) as ?prediction)
WHERE {
{
SELECT ?other_vector (COUNT(?common_feature) as ?similarity)
WHERE { vector:0 :has ?common_feature .
?other_vector :has ?common_feature .
} GROUP BY ?other_vector ORDER BY DESC(?similarity) LIMIT 100
}
?other_vector :hasLabel ?label .
}
Is there a way to do this for multiple vectors in a single query?
Unless I'm overlooking something, you can do this by replacing the URI vector:0 with a variable, like so:
SELECT ?vector (AVG(?label) as ?prediction)
WHERE {
{
SELECT ?vector ?other_vector (COUNT(?common_feature) as ?similarity)
WHERE { ?vector :has ?common_feature .
?other_vector :has ?common_feature .
FILTER(?vector != ?other_vector)
} GROUP BY ?other_vector ORDER BY DESC(?similarity) LIMIT 100
}
?other_vector :hasLabel ?label .
}
I added a filter condition to check that ?vector and ?other_vector are not equal, whether that is necessary is up to you of course :)
If you need to restrict the list of vectors for which you want to find a match, you can use a VALUES clause to restrict possible bindings for ?vector:
VALUES ?vector { vector:0 vector:1 ... }