Suppose we have an ontology recording log events, with 2 distinct types of events: info and warning. Each entry is linked to the previous one via the non-transitive property hasPreviousEvent as shown below:
For all the info nodes I would like to retrieve the closest error node, no matter how many hops back it resides. Ideally, for the above sample dataset, I would like to have the following resultset:
entry
prev
:info_2
:error_1
:info_3
:error_2
:info_4
:error_2
Using SPARQL property paths, the following query
SELECT * WHERE {
?entry rdf:type :Info ;
:hasPreviousEntry* ?prev .
?prev rdf:type :Error .
} ORDER BY ?entry
reasonably retrieves the following resultset:
entry
prev
:info_2
:error_1
:info_3
:error_1
:info_3
:error_2
:info_4
:error_1
:info_4
:error_2
I cannot find how I could have the desired results. Any help would be highly appreciated.
Check that there doesn't exist another error linked by ?entry which in turn links to ?prev in at least one step.
SELECT * WHERE {
?entry rdf:type :Info ;
:hasPreviousEntry* ?prev .
?prev rdf:type :Error .
FILTER NOT EXISTS {
?entry :hasPreviousEntry* [ rdf:type :Error ;
:hasPreviousEntry+ ?prev ] .
}
} ORDER BY ?entry
Related
I made this ontology:
SensorOntology:MedicalCabinet-01 rdf:type owl:NamedIndividual ,
SensorOntology:MedicalCabinetSensor ;
SensorOntology:hasId "57"^^xsd:int ;
SensorOntology:hasValue "0"^^xsd:int .
I am trying to write a query to get the type of MedicalCabinet-01 which is MedicalCabinetSensor by given id number. However, I am printing owl:NamedIndividual and SensorOntology:MedicalCabinetSensor. Is it anyway I print just SensorOntology:MedicalCabinetSensor. This is my query:
SELECT DISTINCT ?sensor ?sensorclass
WHERE {?sensor :hasId "100"^^xsd:int.
?sensor rdf:type ?sensorclass}
There are multiple ways to ignore results, so it's not clear which one you want to use - especially since some are quite obvious. Here are two options:
As you tagged it with Jena, use Java and ignore resources whose URI matches owl:NamedIndividual.
Use a FILTER in SPARQL, i.e. add FILTER(?sensorclass != owl:NamedIndividual) to the graph pattern of the SPARQL query.
Indeed, there are multiple ways. Here's another:
SELECT DISTINCT ?sensor ?sensorclass
WHERE {?sensor :hasId "100"^^xsd:int.
?sensor rdf:type ?sensorclass
FILTER ( strstarts(str(?sensorclass), "[sensor ontology URI]") )
}
I tried the following query in sparql:
Select distinct (count(?jel) AS ?jelCount )
Where {
?jel a skos:Concept .
?jel skos:prefLabel ?label .
Filter not Exists {
?jel skos:narrower ?narrower .
?jel skos:notation ?notation .
}
}
However it does not give me the answer i want, it actually filter nothing.
However if i write:
Select distinct (count(?jel) AS ?jelCount )
Where {
?jel a skos:Concept .
?jel skos:prefLabel ?label .
Filter not Exists {
?jel skos:narrower ?narrower .
}
Filter not Exists {
?jel skos:notation ?notation .
}
}
Then i get the answer that i want.
I am not able to explain why ? Can someone enlighten me on this please?
In SPARQL the entirety of each pattern (denoted by { }) must match to have an effect.
So your first query asks for items where both of the skos:narrower and skos:notation triples do not exist for an item because they are in the same FILTER NOT EXISTS pattern. Presumably there are no items where both of those triples exist for an item in your data and thus nothing is filtered out.
However in your second query you ask for items where either of the skos:narrower or skos:notation do not exist (because each is in a separate FILTER NOT EXISTS pattern). As there are some of these triples for some items in your data then some things are filtered out.
Any help in my learning will be highly appreciated.
Problem statement:
Need to print list of tourist places in various cities
I have http://dbpedia.org/page/Category:Tourism_by_city category which i have to explore. The problem is this category is a skos:broader of various other categories like http://dbpedia.org/page/Category:Tourism_in_Bratislava which in itself is a skos:broader of http://dbpedia.org/page/Category:Visitor_attractions_in_Bratislava which contains dcterms:subject property and which is the list of tourist places.
I have to explore all cities starting from Tourism_by_city category.
What I have done
SELECT DISTINCT ?places
WHERE {
?entity skos:broader* <http://dbpedia.org/resource/Category:Tourism_by_city> .
?places dcterms:subject ?entity
}
Problem:
skos:broader is further exploring the graph, i want to restrict it till Visitor_attractions level. Also skos:broader is exploring all the categories but i want it to explore for just Visitor_attractions category.
Level 1 : Tourism_by_city - > explore all skos:broader of
Level 2 : Tourism_by_xxxcity -> explore only category:Vistors_attractions_by_xxxcity
Level 3 : Do not explore further.
Is this achievable ?
Please do let me know if question is unclear. Thanks
Finally solved the question, I don't know whether this is the only viable option:
SELECT DISTINCT (str(?city) as ?City) (str(?label) as ?Attractions)
WHERE {
?entity skos:broader <http://dbpedia.org/resource/Category:Tourism_by_city> .
?places skos:broader ?entity .
?places rdfs:label ?city .
FILTER langMatches(lang(?city),"en") .
?attractions dcterms:subject ?places .
?attractions rdfs:label ?label .
FILTER langMatches(lang(?label),"en").
FILTER (if (isliteral(?city ), contains(str(?city ), "Visitor"), false))
}
ORDER BY ASC(?city)
Is it possible to have a definition of an resource (from DBpedia) with a SPARQL query? I want to have something like the TBox and ABox that are shown in (Conceptual) Clustering methods for
the Semantic Web: issues and applications (slides 10–11). For example, for DBpedia resource Stephen King, I would like to have:
Stephen_King : Person ⊓ Writer ⊓ Male ⊓ … (most specific classes)
You can use a query like the following to ask for the classes of which Stephen King is an instance which have no subclasses of which Stephen King is also an instance. This seems to align well with the idea of “most specific classes.” However, since (as far as I know) there's no reasoner attached to the DBpedia SPARQL endpoint, there may be subclass relationships that could be inferred but which aren't explicitly present in the data.
select distinct ?type where {
dbr:Stephen_King a ?type .
filter not exists {
?subtype ^a dbr:Stephen_King ;
rdfs:subClassOf ?type .
}
}
SPARQL results
Actually, since every class is an rdfs:subClassOf itself, you might want to add another line to that query to exclude the case where ?subtype and ?type are the same:
select distinct ?type where {
dbr:Stephen_King a ?type .
filter not exists {
?subtype ^a dbr:Stephen_King ;
rdfs:subClassOf ?type .
filter ( ?subtype != ?type )
}
}
SPARQL results
If you actually want a result string like the one shown in those slides, you could use values to bind a variable to dbr:Stephen_King, and then use some grouping and string concatenation to get something nicer looking (sort of):
select
(concat( ?person, " =\n", group_concat(?type; separator=" AND\n")) as ?sentence)
where {
values ?person { dbr:Stephen_King }
?type ^a ?person .
filter not exists {
?subtype ^a ?person ;
rdfs:subClassOf ?type .
filter ( ?subtype != ?type )
}
}
group by ?person
SPARQL results
http://dbpedia.org/resource/Stephen_King =
http://dbpedia.org/class/yago/AuthorsOfBooksAboutWritingFiction AND
http://dbpedia.org/ontology/Writer AND
http://schema.org/Person AND
http://xmlns.com/foaf/0.1/Person AND
http://dbpedia.org/class/yago/AmericanSchoolteachers AND
http://dbpedia.org/class/yago/LivingPeople AND
http://dbpedia.org/class/yago/PeopleFromBangor,Maine AND
http://dbpedia.org/class/yago/PeopleFromPortland,Maine AND
http://dbpedia.org/class/yago/PeopleFromSarasota,Florida AND
http://dbpedia.org/class/yago/PeopleSelf-identifyingAsAlcoholics AND
http://umbel.org/umbel/rc/Artist AND
http://umbel.org/umbel/rc/Writer AND
http://dbpedia.org/class/yago/20th-centuryNovelists AND
http://dbpedia.org/class/yago/21st-centuryNovelists AND
http://dbpedia.org/class/yago/AmericanHorrorWriters AND
http://dbpedia.org/class/yago/AmericanNovelists AND
http://dbpedia.org/class/yago/AmericanShortStoryWriters AND
http://dbpedia.org/class/yago/CthulhuMythosWriters AND
http://dbpedia.org/class/yago/HorrorWriters AND
http://dbpedia.org/class/yago/WritersFromMaine AND
http://dbpedia.org/class/yago/PeopleFromDurham,Maine AND
http://dbpedia.org/class/yago/PeopleFromLisbon,Maine AND
http://dbpedia.org/class/yago/PostmodernWriters
I am using SPARQL query on DBpedia into a Prolog project and I have a doubt. I would know if a word is, most probably, a NAME OF A PERSON (something like: John, Mario) or a PLACE (like a city: Rome, London, New York).
I have implement the following two queries, the first gives me the number of persons having a specific name, and the second gives me the number of places having a specific name.
1) Query for a PERSON NAME:
select COUNT(?person) where {
?person a dbpedia-owl:Person .
{ ?person foaf:givenName "John"#en }
UNION
{ ?person foaf:surname "John"#en }
}
For the name John, I obtain the following output: callret-0: 7313, so I think that it has found 7313 instances for the proper name John. Is it right?
2) Query for a PLACE NAME:
select COUNT(?place) where {
?place a dbpedia-owl:Place .
{ ?x rdfs:label "John"#en }
}
The problem is that, as you can see in the previous “place” query, I have inserted John as parameter, which is not a place name but a proper name of persons, but I obtain the following strange result: callret-0: 81900104
The problem is that, in this way, if I compare the output of the previous two queries, it seems that John is a place and not a person name! This is not good for my scope; I have tried with other personal names and it always happens that the place query gives me a bigger output than the name query.
Why? What am I missing? Are there some errors in my queries? How can I solve it to have a correct result?
Actually, when I run the query you provided:
select COUNT(?place) where {
?place a dbpedia-owl:Place .
{ ?x rdfs:label "John"#en }
}
I get the result 93027312, not 81900104, but that does not really matter much. The strange results arise because ?x and ?place don't have to be bound to the same thing, so you are getting all the dbpedia-owl:Places and counting them, but the number of result rows is the number of dbpedia-owl:Place multiplied by the number of things with rdfs:label "John#en":
select COUNT(?place) where { ?place a dbpedia-owl:Place }
=> 646023
select COUNT(?x) where { ?x rdfs:label "John"#en }
=> 144
646023 × 144 = 93027312
If you actually ask for dbpedia-owl:Places that have the rdfs:label "John#en", you'll get no results:
select COUNT(?place) as ?numPlaces where {
?place a dbpedia-owl:Place ;
rdfs:label "John"#en .
}
SPARQL results
Also, you might consider using dbpprop:name instead of rdfs:label. Some results seem like they are more useful that way. For instance, let us find places called "Springfield". If we ask for places with that name we get no results:
select * where {
?place a dbpedia-owl:Place ;
rdfs:label "Springfield"#en .
}
SPARQL results
However, if we modify the query and use dbpprop:name, we get 17. Some of these are duplicates though, so you might have to do something else to remove duplicates. The point, though, is that dbpprop:name got some results, and rdfs:label didn't.
select * where {
?place a dbpedia-owl:Place ;
dbpprop:name "Springfield"#en .
}
SPARQL results
You can even use dbpprop:name in working with the names of persons, although it's not as useful, because the dbpprop:name value for most persons is their entire name. To find persons with the given name John using dbpprop:name requires a query like:
select * where {
?place a dbpedia-owl:Person ;
dbpprop:name ?name .
FILTER( STRSTARTS( str( ?name ), "John" ) )
}
(or you could use CONTAINS instead of STRSTARTS), but this becomes much more expensive, because it has to select all persons and their names, and then filter through that set. Being able to select persons based on a specific name (e.g., with foaf:givenName) is much more efficient.