I have multiple trees where nodes are linked with hasParent and each node has some particular color. I need to filter a tree by a color and extract the topmost elements (exclude nested elements after filtering).
Here is an example of my data:
The result I need is: [A, B, I].
I know how to implement basic tree filter that returns [A, B, I, J, L, O]:
SELECT DISTINCT ?s WHERE {
?s <http://looneytunes-graph.com/color> "yellow"^^xsd:string
}
Is there a way to implement such additional filtering? or do I need to rethink my solution and use something else instead of graph db (AWS Neptune)?
I'm testing it with https://sparql-playground.sib.swiss/data and the following data:
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://looneytunes-graph.com/A> <http://looneytunes-graph.com/color> "yellow"^^xsd:string .
<http://looneytunes-graph.com/B> <http://looneytunes-graph.com/color> "yellow"^^xsd:string .
<http://looneytunes-graph.com/C> <http://looneytunes-graph.com/color> "green"^^xsd:string .
<http://looneytunes-graph.com/D> <http://looneytunes-graph.com/color> "red"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/A> .
<http://looneytunes-graph.com/E> <http://looneytunes-graph.com/color> "blue"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/A> .
<http://looneytunes-graph.com/F> <http://looneytunes-graph.com/color> "blue"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/B> .
<http://looneytunes-graph.com/G> <http://looneytunes-graph.com/color> "green"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/B> .
<http://looneytunes-graph.com/H> <http://looneytunes-graph.com/color> "red"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/C> .
<http://looneytunes-graph.com/I> <http://looneytunes-graph.com/color> "yellow"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/C> .
<http://looneytunes-graph.com/J> <http://looneytunes-graph.com/color> "yellow"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/D> .
<http://looneytunes-graph.com/K> <http://looneytunes-graph.com/color> "green"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/D> .
<http://looneytunes-graph.com/L> <http://looneytunes-graph.com/color> "yellow"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/F> .
<http://looneytunes-graph.com/M> <http://looneytunes-graph.com/color> "red"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/G> .
<http://looneytunes-graph.com/N> <http://looneytunes-graph.com/color> "blue"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/G> .
<http://looneytunes-graph.com/O> <http://looneytunes-graph.com/color> "yellow"^^xsd:string ;
<http://looneytunes-graph.com/hasParent> <http://looneytunes-graph.com/I> .
SELECT DISTINCT ?s WHERE {
?s <http://looneytunes-graph.com/color> "yellow"^^xsd:string .
FILTER NOT EXISTS {
?s hasParent+ [<http://looneytunes-graph.com/color> "yellow"^^xsd:string] .
}
}
With this query you are filtering out the nodes having (a parent node having a parent node having...) a yellow parent node.
Related
I know there's some answers from Query SPARQL resulting level 1 hierarchy and SPARQL Query - get top-level classes of a dataset
But this isn't enough for what I'm trying to do. I have the class Category, subclass of owl:Thing, and the query
SELECT DISTINCT ?cls
WHERE {
?cls a owl:Class .
FILTER NOT EXISTS {
?cls rdfs:subClassOf ?sup .
FILTER(?sup != owl:Thing)
}
}
works fine for other classes without restrictions but it doesn't return Category because Category has restrictions, which this query sees them as separate classes. My Category class looks like this:
:Category rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ,
[ rdf:type owl:Restriction ;
owl:onProperty :hasConfidence ;
owl:minCardinality "0"^^xsd:nonNegativeInteger
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :hasIntensity ;
owl:minCardinality "0"^^xsd:nonNegativeInteger
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :hasConfidence ;
owl:maxCardinality "1"^^xsd:nonNegativeInteger
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :hasIntensity ;
owl:maxCardinality "1"^^xsd:nonNegativeInteger
] ;
rdfs:comment """Category refers to the classification used to annotate the emotion.
This can be further expanded to add support to new categories."""#en ;
rdfs:label "Category"#en .
How can I modify the query to add these top-level classes that are "subclasses" of some restrictions? I need a FILTER for those restrictions but I don't know how to go into this. I tried doing
SELECT DISTINCT ?cls
WHERE
{
{
?cls a owl:Class .
FILTER NOT EXISTS {
?cls rdfs:subClassOf ?sup .
FILTER(?sup != owl:Thing)
}
}
UNION
{ ?cls rdfs:subClassOf owl:Thing }
}
and it works but that implies that Category has to be EXPLICITLY subclass of owl:Thing, which isn't always the case in a lot of ontologies.
I figured it out. Here's the query for anyone who's having trouble with this like me:
SELECT DISTINCT ?cls
WHERE
{
?cls a owl:Class .
FILTER NOT EXISTS {
?cls rdfs:subClassOf ?sup .
FILTER(?sup != owl:Thing) .
FILTER NOT EXISTS {
?sup a owl:Restriction .
}
}
FILTER(?cls != owl:Thing) # We get rid of the root class from the query results
}
Basically, all I needed was a filter for the owl:Restriction class types. I also added a filter to get rid of owl:Thing from the query results. With this query I'm able to get the Category class from my ontology, which is part of the top-layer / level 1 hierarchy.
The example ontology has two classes (:MyClass and :Value) and two properties (:MyObjProp and :MyDataProp).
:MyClass
a owl:Class ;
a sh:NodeShape ;
rdfs:subClassOf owl:Thing ;
.
:MyDataProp
a owl:DatatypeProperty ;
rdfs:domain :MyClass ;
rdfs:range xsd:string ;
.
:MyObjProp
a owl:ObjectProperty ;
rdfs:domain :MyClass ;
rdfs:range :Value ;
.
:Value
a owl:Class ;
rdfs:subClassOf owl:Thing ;
.
Some instances were added.
:MyClass_1
a :MyClass ;
:MyDataProp :Value_1 ;
:MyObjProp :Value_1 ;
.
:MyClass_2
a :MyClass ;
:MyObjProp :Value_2 ;
.
:Value_1
a :Value ;
.
:Value_2
a :Value ;
.
A NodeShape :NodeShapeRule with a sh:rule (:SPARQLRule_1) was created. This rule creates new triples. With the sh:condition the rule should be restricted to a subset of targets.
:NodeShapeRule
a sh:NodeShape ;
sh:rule :SPARQLRule_1 ;
sh:targetClass :MyClass ;
.
:SPARQLRule_1
a sh:SPARQLRule ;
sh:condition :NodeShapeConditionSPARQL ;
sh:construct """
PREFIX : <http://example.org/ex#>
CONSTRUCT
{
$this :MyDataProp \"New input\" .
}
WHERE
{
$this :MyObjProp ?p .
}
""" ;
.
For the restriction two equivalent NodeShapes were defined. The first constraint works with sh:property, the other uses sh:sparql.
:NodeShapeConditionProperty
a sh:NodeShape ;
sh:property [
sh:path :MyObjProp ;
sh:description "NodeShapeConditionProperty" ;
sh:hasValue :Value_1 ;
] ;
sh:targetClass :MyClass ;
.
:NodeShapeConditionSPARQL
a sh:NodeShape ;
sh:sparql [
sh:message "NodeShapeConditionSPARQL" ;
sh:prefixes <http://example.org/ex> ;
sh:select """
PREFIX : <http://example.org/ex#>
SELECT $this
WHERE
{
$this :MyObjProp ?prop .
}
""" ;
] ;
sh:targetClass :MyClass ;
.
While doing inferencing with Topbraid Composer I received different results for both solutions. Only the solution with sh:property provides the expected response. Please, can someone explain me this behavior?
:MyClass_1 :MyDataProp "New input"
The right explanation is that the SPAQRL query produces a constraint violation for each result (row) in SELECT query. So if the SPARQL query returns no result (rows) then all is fine and the rule will fire. The reason for this design is that this enables SPARQL queries to return more information about the violation, e.g. the focus node ($this) and the value node (?value).
Changing the :NodeShapeConditionSPARQL it produces violation for not existing results and then both solutions behave in the same manner.
:NodeShapeConditionSPARQL
a sh:NodeShape ;
sh:sparql [
sh:message "NodeShapeConditionSPARQL" ;
sh:prefixes <http://example.org/ex> ;
sh:select """
PREFIX : <http://example.org/ex#>
SELECT $this
WHERE
{
FILTER NOT EXISTS { $this :MyObjProp ?anyProp } .
}
""" ;
] ;
sh:targetClass :MyClass ;
.
Consider the following example:
:rangeA :lowerLimit :LeftMarginA ;
:upperLimit :RightMarginA .
:rangeB :lowerLimit :LeftMarginB ;
:upperLimit :RightMarginB .
:LeftMarginA :hasValue 20 ;
:RightMarginA :hasValue 80 .
:LeftMarginB :hasValue 30 ;
:RightMarginB :hasValue 60 .
How to get inference results using SPARQL or SWRL
:rangeA :Contains :rangeB
My idea is:
if (:LeftMarginB >= :LeftMarginA)
&& (:RightMarginB <= :RightMarginA)
then :rangeA :contains :rangeB
But how do I write this SPARQL or SWRL statement?
Thanks for help.
If you can write a SELECT query that selects one range that contains another, it's just one more step to convert it into a CONSTRUCT WHERE query that generates the triple that captures your inference. For instance:
Some Data
#prefix : <urn:ex:>
:x :lower 30 ; :upper 60 .
:y :lower 20 ; :upper 80 .
A query
prefix : <urn:ex:>
construct {
?a :contains ?b
} where {
?a :lower ?la ; :upper ?ua .
?b :lower ?lb ; :upper ?ub .
filter ( ?lb < ?la && ?ua < ?ub )
}
The result
#prefix : <urn:ex:> .
:x :contains :y .
I've tested and this does work:
prefix : <#>
CONSTRUCT { ?rangeA :contains ?rangeB . }
WHERE {
{
SELECT ?rangeA ?rangeB
WHERE {
?rangeA :lowerLimit ?LeftMarginA ;
:upperLimit ?RightMarginA .
?rangeB :lowerLimit ?LeftMarginB ;
:upperLimit ?RightMarginB .
?LeftMarginA :hasValue ?valueLA.
?RightMarginA :hasValue ?valueRA.
?LeftMarginB :hasValue ?valueLB.
?RightMarginB :hasValue ?valueRB.
Filter ((?valueLB >= ?valueLA) && (?valueRB <= ?valueRA)
&& (?rangeA !=?rangeB))
}
}
}
But that doesn't take into account the inclusion of the boundary.
If consider boundary inclusion like :
:LeftMarginA :hasValue 20 ;
:inclusive True.
:RightMarginA :hasValue 80 ;
:inclusive False.
How can SPARQL statements be modified to work properly?
Thank you all, the final solution is as follows:
#-----rdf data
#prefix : <#> .
:rangeA :lowerLimit 20 ;
:lowerLimitInclusiveA false ;
:upperLimit 80 ;
:upperLimitInclusiveA false .
:rangeB :lowerLimit 20.5 ;
:lowerLimitInclusiveB false ;
:upperLimit 60 ;
:upperLimitInclusiveB false .
#---sparql query ========================
prefix : <#>
CONSTRUCT { ?rangeA :contains ?rangeB . }
WHERE {
{
SELECT ?rangeA ?rangeB
WHERE {
?rangeA :lowerLimit ?LeftMarginA ;
:lowerLimitInclusiveA ?lowerA ;
:upperLimit ?RightMarginA ;
:upperLimitInclusiveA ?upperA .
?rangeB :lowerLimit ?LeftMarginB ;
:lowerLimitInclusiveB ?lowerB ;
:upperLimit ?RightMarginB ;
:upperLimitInclusiveB ?upperB .
Filter (if(?lowerA,?LeftMarginB>=?LeftMarginA, ?LeftMarginB>?LeftMarginA)
&& if(?upperA, ?RightMarginB<=?RightMarginA, ?RightMarginB<?RightMarginA)
&& (?rangeA!= ?rangeB))
}
}
}
I did not get the right sentence to ask the question.
I would like to explain my problem using a sample data.
let's say the triples are as below.
#prefix skos: <http://www.w3.org/2004/02/skos/core#> .
#prefix xs: <http://www.w3.org/2001/XMLSchema#> .
#prefix p0: <http://www.mlacustom.com#> .
#prefix p2: <http://www.mla.com/term/> .
_:bnode7021016689601753065 p0:lastModifiedDateTime "2018-09-14T12:55:38"^^<xsd:dateTime> ;
p0:lastModifiedUser "admin"^^xs:string .
<http://www.mla.com/name/4204078359> p0:hasClassingFacet "http://www.mla.com/facet/RA"^^xs:string ;
p0:type "Normal"^^xs:string ;
p0:classification _:bnode3452184423513029143 ,
_:bnode6827572371999795686 ;
p0:recordType "Name"^^xs:string ;
p0:recordNumber "4204078359"^^xs:string ;
p0:stdDescriptor "classification111111"^^xs:string ;
p0:establishedBy "admin"^^xs:string ;
skos:prefLabel "classification111111"^^xs:string ;
p0:createdBy "admin"^^xs:string ;
a skos:Concept ;
p0:createdDate "2018-09-14T12:55:38"^^<xsd:dateTime> ;
p0:establishedDate "2018-09-14T12:55:38"^^<xsd:dateTime> ;
p0:hasRAsubFacet "http://www.mla.com/subfacet/classing-subject-authors"^^xs:string ;
p0:lastModifiedDate "2018-09-14T12:55:38"^^<xsd:dateTime> ;
p0:lastModifiedDetails _:bnode7021016689601753065 ;
p0:isProblematic "N,N"^^xs:string ;
p0:lastModifiedBy "admin"^^xs:string ;
p0:status "established"^^xs:string .
_:bnode3452184423513029143 p0:literature p2:1513 ;
p0:timePeriod p2:1005 ;
p0:language p2:3199 .
_:bnode6827572371999795686 p0:literature p2:11307 ;
p0:timePeriod p2:1009 ;
p0:language p2:31 .
please have a look at the p0:classification it has two blank nodes and both the blank nodes has triples with p0:literature, p0:timePeriod, p0:language
Now I want to write a SPARQL query where
(
(p0:literature is p2:1513 AND p0:timePeriod is p2:1005) AND
(p0:literature is p2:11307 AND p0:timePeriod is p2:1009)
)
As per the above scenario it should return me the http://www.mla.com/name/4204078359 subject
Classification can have any number of blank nodes.
Here is one of the solutions. It is possible to find many different queries. This one is explicit.
SELECT ?s WHERE {
?s p0:classification ?o1 .
?s p0:classification ?o2 .
?o1 p0:literature p2:1513 ;
p0:timePeriod p2:1005 .
?o2 p0:literature p2:11307 ;
p0:timePeriod p2:1009 .
}
The following query translates a word to a certain language:
SELECT DISTINCT ?translation WHERE {
?entries a lemon:LexicalEntry .
?entries rdfs:label "apple"#en .
?entries lemon:sense ?sense .
?sense lexinfo:translation ?translation .
filter contains(str(?translation),"HI")
}
But how can I retrieve the label for the translation, which is a LexicalSense as far I can tell
The way up and the way down is one and the same (as Heraclitus had said):
SELECT DISTINCT ?label WHERE {
?original_entry rdfs:label "apple"#en .
?original_entry lemon:sense ?original_sense .
?original_sense
lexinfo:translation
?translated_sense .
?translated_entry lemon:sense ?translated_sense .
?translated_entry rdfs:label ?label .
FILTER (lang(?label) = "hi")
}
Try it!
This page describes data model and provides some example queries.