Sparql two-nested-opt dawg test query results hard to understand - sparql

The DAWG test query two-nested-opt.rq is like this:
PREFIX : <http://example/>
SELECT *
{
:x1 :p ?v .
OPTIONAL
{
:x3 :q ?w .
OPTIONAL { :x2 :p ?v }
}
}
The test data is:
#prefix : <http://example/> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
:x1 :p "1"^^xsd:integer .
:x2 :p "2"^^xsd:integer .
:x3 :q "3"^^xsd:integer .
:x3 :q "4"^^xsd:integer .
If I run the query, the expected results is just one record with ?v=1 (for short). Don't really understand it since commenting the second optional, the result is two records:
v=1, w=3
v=1, w=4
Some possible explanations I found mention the second optional is a no-op since the ?v bindings don't match between second optional and the main bgp. But don't get how that explains it. Shouldn't the results of first optional be always included in the solution whatever the result of second optional is?

This test case is about evaluation being functional (also called bottom-up) and how early (inner-most) setting of ?v affects the outcome. In the test, the inner most setting of ?v then blocks the first OPTIONAL and the ?w = 3 and ?w = 4 are not results.
It is the case of the general situation of having an outer ?v (left side of the OPTIONAL), then an OPTIONAL part that does not mention ?v which itself has an OPTIONAL using ?v.
If the query is thought of top-down, the answers would be different.
Evaluation is:
:x3 :q ?w leftjoin :x2 :p ?v
Two rows:
?w = 3; ?v = 2
?w = 4; ?v = 2
:x1 :p ?v
?v = 1
Now left join "?v = 1" with "?w = 3; ?v = 2" -- The OPTIONAL does not join so the result is one row, "?v = 1" and no ?w binding.
If the ":x2 :p ?v" is omitted, the first
:x3 :q ?w
Two rows:
?w = 3
?w = 4
both of which join with ?v = 1, giving two rows of ?v and ?w.

Related

Type of returned value in SPARQL Query

Is it possible to know the type of the return values in a SPARQL query?
For example, is there a function to define the type of ?x ?price ?p
in the following query?
SELECT DISTINCT ?x ?price ?p
WHERE {
?x a :Product .
?x :price ?price .
?x ?p ?o .
}
I want to know that
typeOf(x) = resource
typeOf(?p) = property
typeOf(?price) = property target etc.
datatype(?x)
The datatype function will tell you whether a result is a resource or a literal and in the latter case tell you which datatype it has exactly.
For example, the following query on https://dbpedia.org/sparql...
SELECT DISTINCT ?x ?code ?p datatype(?x) datatype(?code) datatype(?p)
WHERE {
?x a dbo:City.
?x dbo:areaCode ?code .
?x ?p ?o .
} limit 1
...will return:
x
code
p
callret-3
callret-4
callret-5
http://dbpedia.org/resource/Aconchi
"+52 623"
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
http://www.w3.org/2001/XMLSchema#anyURI
http://www.w3.org/2001/XMLSchema#string
http://www.w3.org/2001/XMLSchema#anyURI
However this will not differentiate between "resource" and "property" because a resource may be a property. What you probably mean is "individual" and "property" but even a property can be treated as an individual, for example in the triple rdfs:label rdfs:label "label".
However you can always query the rdf:type of a resource, which may give you rdf:Property, owl:DatatypeProperty or owl:ObjectProperty.

how to remove duplicates in sparql query

I wrote this query and return list of couples and particular condition. ( in http://live.dbpedia.org/sparql)
SELECT DISTINCT ?actor ?person2 ?cnt
WHERE
{
{
select DISTINCT ?actor ?person2 (count (?film) as ?cnt)
where {
?film dbo:starring ?actor .
?actor dbo:spouse ?person2.
?film dbo:starring ?person2.
}
order by ?actor
}
FILTER (?cnt >9)
}
Problem is that some rows is duplicate.
example:
http://dbpedia.org/resource/George_Burns http://dbpedia.org/resource/Gracie_Allen 12
http://dbpedia.org/resource/Gracie_Allen http://dbpedia.org/resource/George_Burns 12
how to remove these duplications?
I added gender to ?actor but it damage current result.
Natan Cox's answer shows the typical way to exclude these kind of pseudo-duplicates. The results aren't actually duplicates, because in one, e.g., George Burns is the ?actor, and in the other he is the ?person2. In many cases, you can add a filter to require that the two things are ordered, and that will remove the duplicate cases. E.g., when you have data like:
:a :likes :b .
:a :likes :c .
and you search for
select ?x ?y where {
:a :likes ?x, ?y .
}
you can add filter(?x < ?y) to enforce an ordering between the between ?x and ?y which will remove these pseudo-duplicates. However, in this case, it's a bit trickier, since ?actor and ?person2 aren't found using the same critera. If DBpedia contains
:PersonB dbo:spouse :PersonA
but not
:PersonA dbo:spouse :PersonB
then the simple filter won't work, because you'll never find the triple where the subject PersonA is less than the object PersonB. So in this case, you also need to modify your query a bit to make the criteria symmetric:
select distinct ?actor ?spouse (count(?film) as ?count) {
?film dbo:starring ?actor, ?spouse .
?actor dbo:spouse|^dbo:spouse ?spouse .
filter(?actor < ?spouse)
}
group by ?actor ?spouse
having (count(?film) > 9)
order by ?actor
(This query also shows that you don't need a subquery here, you can use having to "filter" on aggregate values.) But the important part is using the property path dbo:spouse|^dbo:spouse to find a value for ?spouse such that either ?actor dbo:spouse ?spouse or ?spouse dbo:spouse ?actor. This makes the relationship symmetric, so that you're guaranteed to get all the pairs, even if the relationship is only declared in one direction.
It is not actual duplicates of course since you can look at it from both ways. The way to fix it if you want to is to add a filter. It is a bit of a dirty hack but it only takes on of the 2 rows that are the "same".
SELECT DISTINCT ?actor ?person2 ?cnt
WHERE
{
{
select DISTINCT ?actor ?person2 (count (?film) as ?cnt)
where {
?film dbo:starring ?actor .
?actor dbo:spouse ?person2.
?film dbo:starring ?person2.
FILTER (?actor < ?person2)
}
order by ?actor
}
FILTER (?cnt >9)
}

SPARQL is it possible to bind two variables with their labels with a static text?

This is my query
PREFIX : <http://example.org/rs#>
select ?item (SUM(?similarity) as ?summedSimilarity)
(group_concat(distinct ?becauseOf ; separator = " , ") as ?reason) where
{
values ?x {:instance1}
{
?x ?p ?instance.
?item ?p ?instance.
?p :hasSimilarityValue ?similarity
bind (?p as ?becauseOf)
}
union
{
?x a ?class.
?item a ?class.
?class :hasSimilarityValue ?similarity
bind (?class as ?becauseOf)
}
filter (?x != ?item)
}
group by ?item
in my firstbind clause, I would like to not just bind the variable ?p, but also the variable ?instance. Plus, adding a text like that is why.
so the first bind should result the following results:
?p that is why ?instance
is that possible in SPARQL ?
please don't care about if the data makes sence or not, it is just a query to show you my question
If I understand you correctly, you're just looking for the concat function. As I've mentioned before, you should really browse through the SPARQL 1.1 standard, at least through the table of contents. You don't need to memorize it, but it will give you an idea of what things are possible, and an idea of where to look. Additionally, it's very helpful if you provide sample data that we can work with, because it makes it much clearer to figure out what you're trying to do. The phrasing of your title was not particularly clear, and the question doesn't really provide an example of what you're trying to accomplish. Only because I've seen some of your past questions did I have an idea of what you were aiming for. At any rate, here's some data:
#prefix : <urn:ex:>
:p :hasSimilarity 0.3 .
:A :hasSimilarity 0.6 .
:a :p :b ; #-- is is related to :b
a :A . #-- and is an :A .
:c :p :b . #-- :c is also related to :b
:d a :A . #-- :d is also an :A .
:e :p :b ; #-- :e is related to :b
a :A . #-- and is also an :A .
And here's the query and its results. You just use concat to join the str form of your variables with the appropriate strings and then bind the result to the variable.
prefix : <urn:ex:>
select ?item
(sum(?factor_) as ?factor)
(group_concat(distinct ?reason_; separator=", ") as ?reason)
{
values ?x { :a }
{ ?x ?p ?instance .
?item ?p ?instance .
?p :hasSimilarity ?factor_ .
bind(concat("has common ",str(?p)," value ",str(?instance)) as ?reason_) }
union
{ ?x a ?class.
?item a ?class.
?class :hasSimilarity ?factor_ .
bind(concat("has common class ",str(?class)) as ?reason_)
}
filter (?x != ?item)
}
group by ?item
-----------------------------------------------------------------------------------
| item | factor | reason |
===================================================================================
| :c | 0.3 | "has common urn:ex:p value urn:ex:b" |
| :d | 0.6 | "has common class urn:ex:A" |
| :e | 0.9 | "has common urn:ex:p value urn:ex:b, has common class urn:ex:A" |
-----------------------------------------------------------------------------------

sparql to retrieve the value of a min constraint

How can I retrieve a min constraint on a class' attribute using sparql? I have value min 1000 decimal, and I would like to get 1000
In a hypothetical world that you have such a statement:
Class: X subClassOf: hasObjectProperty min 1 Y
If you write a SPARQL query as:
SELECT *
WHERE {
?s rdfs:subClassOf ?o.
}
You must extract all the refs:subClassOf axioms. However, if you need to precise and know which ones have cardinality restrictions, you need to go further:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <http://example.com#>
SELECT *
WHERE {
?s rdfs:subClassOf ?o.
?o ?x ?y.
filter(?s = :X)
}
Among others, you can see the following result:
As you can see, there are 2 relevant items, one is Y and one is the number presented as a non-negative integer. Therefore, one way to get each item is to put a filter for ?x in the SPARQL query and get each one one by one out. For example, filter owl:onClass will give you ?y:
prefix : <http://example.com#>
SELECT *
WHERE {
?s rdfs:subClassOf ?o.
?o owl:onClass ?y.
filter(?s = :X)
Here is the sparql query I used following Artemis' answer
SELECT ?min
WHERE {?s rdfs:subClassOf ?o.
?o owl:minQualifiedCardinality ?min.
FILTER(?s = :value) }
And with jena, I use getLiteral("min").getFloat();

select the negative of a SPARQL query

Is possible to select the "negative" of a sparql query?
For instance, consider the following RDF data, query and desired result:
knowledge base:
#prefix gr:<http://purl.org/goodrelations/v1#>.
#prefix rdfs:<http://www.w3.org/2000/01/rdf-schema#>.
:prod_A :hasProp :propA.
:prod_B :hasProp :propB.
:propB rdfs:label "Hello".
:prod_C :hasProp :propC.
:prod_D :hasProp :propD.
Imaginary Query:
PREFIX gr:<http://purl.org/goodrelations/v1#>
SELECT ?prod WHERE
{ !(
?prod ?p ?o.
?o ?p2 ?o2.
) }
Ideal Result:
| ?prod |
|---------|
| :prod_A |
| :prod_C |
| :prod_D |
is there a way through? (i need it for a delete)
I think MINUS is what you are looking for:
PREFIX gr:<http://purl.org/goodrelations/v1#>
SELECT ?prod WHERE
{
?prod ?p ?o.
MINUS { ?o ?p2 ?o2 }
}
It takes the things matched by the left hand side (?prod ?p ?o) and removes any that correspond to items matched by the MINUS pattern.
Note this doesn't give your desired answer because the ?prod ?p ?o pattern matches everything including the linked property (:propB rdfs:label "Hello") that you aren't interested in for your results
To get your desired answer you need to make the first part of the query more specific like so:
PREFIX :<http://example.org/>
PREFIX gr:<http://purl.org/goodrelations/v1#>
SELECT ?prod WHERE
{
?prod :hasProp ?o.
MINUS { ?o ?p2 ?o2 }
}
Here I changed the ?p variable to be the :hasProp constant instead. With this query I get your desired answer.
NB - You didn't define the empty prefix in your example so I invented one to make the query valid and so I could test that it worked
Another way is to use FILTER NOT EXISTS
SELECT ?prod WHERE
{
?prod :hasProp ?o.
FILTER NOT EXISTS { ?o rdfs:label "Hello". }
}
which does the first ?prod :hasProp ?o. then checks whether ?o causes ?o rdfs:label "Hello" to match. Use the form you find easiest to understand.