How to get *all* superclasses of a Wikidata entity with SPARQL? - sparql

I am interested in visualizing the Wikidata class hierarchy to create graphs like
I know how I can get direct superclasses of a Wikidata entity. For this I use SPARQL code like:
SELECT ?item ?itemLabel
WHERE
{
wd:Q125977 wdt:P279 ?item.
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
where wdt:P279 denotes the subclass of-property.
However, this direct method requires many single requests to the Wikidata API.
How is it possible to get the same information with a single SPARQL query?
(Note that the example graph above only shows an abbreviated version. The final desired graph of all superclasses is 13 levels deep and has 69 nodes which means 68 single requests, see this jupyter notebook if interested.)

You could use a query like this to create your taxonomy (with labels) as triples directly.
CONSTRUCT {
?item1 wdt:P279 ?item2.
?item1 rdfs:label ?item1Label.
?item2 rdfs:label ?item2Label.
}
WHERE {
SELECT ?item1 ?item2 ?item1Label ?item2Label
WHERE {
wd:Q125977 (wdt:P279*) ?item1, ?item2.
FILTER(EXISTS { ?item1 wdt:P279 ?item2. })
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
}

I think you need a query like the following:
SELECT ?class ?classLabel ?superclass ?superclassLabel
WHERE
{
wd:Q125977 wdt:P279* ?class.
?class wdt:P279 ?superclass.
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
where wdt:P279* is a zero-or-more path connecting a class with (a superclass of) one of its superclasses.
This will generate a mapping "class->superclass" containing all what you need for building the graph that you illustrated.

Related

Querying distance units in Sparql - Wikidata example

I would like to know the simplest way to handle units of distance in Sparql. In this Wikidata example I would like to select all the mountains over 8000m; however when I run the text below it also includes all of the mountains over 8000ft. Is it possible to specify that the units I am interested is meters, and for the mountains that are specified in feet, is a conversion to meters necessary?
#Mountains Over 8000m
SELECT ?mountainLabel ?height
WHERE
{
?mountain wdt:P31 wd:Q8502.
?mountain wdt:P2044 ?height.
FILTER(8000 <= ?height)
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en, de". }
}
The psn namespace prefix is used to normalize units of measure. Your query can look like this:
SELECT ?mountainLabel ?height
WHERE
{
?mountain wdt:P31 wd:Q8502.
?mountain p:P2044/psn:P2044/wikibase:quantityAmount ?height .
FILTER(8000 <= ?height)
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en, de". }
}

How to filter wikidata labels in concept search?

I am using the following code to get the wikidata labels for the given concept (e.g., network analysis).
SELECT ?item {
VALUES ?searchTerm { "network analysis" }
SERVICE wikibase:mwapi {
bd:serviceParam wikibase:api "EntitySearch".
bd:serviceParam wikibase:endpoint "www.wikidata.org".
bd:serviceParam wikibase:limit 3 .
bd:serviceParam mwapi:search ?searchTerm.
bd:serviceParam mwapi:language "en".
?item wikibase:apiOutputItem mwapi:item.
?num wikibase:apiOrdinal true.
}
?item (wdt:P279|wdt:P31) ?type
}
ORDER BY ?searchTerm ?num
This returns the following wikidata labels.
wd:Q618079 --> related to electronics
wd:Q4417999 --> related to graph theory (computer science)
wd:Q60640547 --> related to scholary article
I would like to get the wikidata labels that are only related to computer science (i.e. wd:Q4417999 in the above example).
In DBpedia I ran the below query to identify if a word is in computer science.
sparql.setQuery(" ASK { dbc:Network_analysis skos:broader{1,7} dbc:Computer_science } ")
Is it possible to do the same in wikidata (i.e. check if computer science is an ancestor of the given concept and returns only that wikidata label).
If there is a better solution than performing ancestoral search please do suggest me.
I am happy to provide more details if needed.
The sparql query mentioned below solved my issue.
SELECT DISTINCT ?item {
VALUES ?searchTerm { "network analysis"}
SERVICE wikibase:mwapi {
bd:serviceParam wikibase:api "EntitySearch".
bd:serviceParam wikibase:endpoint "www.wikidata.org".
bd:serviceParam wikibase:limit 3 .
bd:serviceParam mwapi:search ?searchTerm.
bd:serviceParam mwapi:language "en".
?item wikibase:apiOutputItem mwapi:item.
?num wikibase:apiOrdinal true.
}
?item (wdt:P279|wdt:P31) ?type
filter exists {?type wdt:P279*/wdt:P361* wd:Q21198}
}
ORDER BY ?searchTerm ?num

How to retrieve the categorical details in Wikidata

I have a list of instances as follows.
myinstances = ['word2vec', 'tf-idf', 'dijkstra's algorithm']
For each myinstance in the above list, I want to find:
1. What are the other instances of `myinstance`'s category (i.e. only one hop)
2. What are the instances of `myinstance`'s category's category (i.e. two hops)
For example, if we consider myinstance = word2vec
What are the other instances of myinstance's category (i.e. only one hop)?
As shown in the figure below the other instances of its immediade ancestor is GloVe.
What are the instances of myinstance's category's category (i.e. two hops)? In other words, what are the instances of embedding (which is two hops away from word2vec) as shown the below figure.
I am just wondering if such query searches can be performed in sparql?
My current code is as follows.
SELECT * {
VALUES ?searchTerm { "word2vec" "tf-idf" "dijkstra's algorithm" }
SERVICE wikibase:mwapi {
bd:serviceParam wikibase:api "EntitySearch".
bd:serviceParam wikibase:endpoint "www.wikidata.org".
bd:serviceParam wikibase:limit 1 .
bd:serviceParam mwapi:search ?searchTerm.
bd:serviceParam mwapi:language "en".
?item wikibase:apiOutputItem mwapi:item.
?num wikibase:apiOrdinal true.
}
?item (wdt:P279|wdt:P31) ?type
}
I am happy to provide more details if needed.

Find the most precise common superclasses between two items

I would like to find the first common superclass(es) between several Wikidata entities.
Let's take a bridge and a cemetery. What is their "smallest" common superclass?
A bridge is a subclass of "architectural structure".
A cemetery is a subclass of "place of worship", which is a subclass of "architectural structure".
---> Their most specialized common class is "architectural structure".
This Sparql query is close to the solution :
SELECT ?classe ?classeLabel WHERE {
wd:Q12280 wdt:P279* ?classe .
FILTER EXISTS { wd:Q39614 wdt:P279* ?classe .}
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
Problem: it returns all common classes between both items, not just the first ones. How could I filter the answer to get what I want?
If this question is of interest to someone else, here is the SPAQL query I finally use to get the Least common subsumers of more than two items. This is a mix between #AKSW response in comments and the answer to that previous question on SO.
SELECT ?lcs ?lcsLabel WHERE {
?lcs ^wdt:P279* wd:Q32815, wd:Q34627, wd:Q16970, wd:Q16560 .
filter not exists {
?sublcs ^wdt:P279* wd:Q32815, wd:Q34627, wd:Q16970, wd:Q16560 ;
wdt:P279 ?lcs .
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
Try it.

Filter by type in Wikidata

This SPARQL request looks for all cities called "Berlin" in Wikidata:
SELECT DISTINCT ?item ?itemLabel ?itemDescription WHERE {
?type (a | wdt:P279) wd:Q515. # Sub-type of city
?item wdt:P31 ?type.
?item rdfs:label "Berlin"#en.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
PROBLEM: It returns zero result.
Meanwhile, the request below correctly finds Q64 (capital and city-state of Germany), but it also returns a lot of other things called Berlin, so I want to filter on cities (then in a future phase I will order these cities by population, but that is outside the scope of this question):
SELECT DISTINCT ?item ?itemLabel ?itemDescription WHERE {
?item rdfs:label "Berlin"#en.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
Note: My code for getting instances of subclasses of city (Berlin is a big city which is subclass of city) seems to work correctly, as illustrated by the results of this query.
It was a Wikidata bug.
According to Wikidata's Jura1, it was a bug in Wikidata caused by someone's experiments with "preferred rank".
Discussion at https://www.wikidata.org/wiki/Wikidata:Project_chat/Archive/2016/09#P31_inconsistency
The bug has been fixed just now.
You can only query for data that is contained in the dataset.
If you try an alternative of your query
SELECT DISTINCT ?item ?itemLabel ?itemDescription ?type1 ?type2 WHERE {
?item rdfs:label "Berlin"#en.
optional{?item rdf:type ?type1 }
optional{?item wdt:P279 ?type2 }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
it returns no types, neither connected by rdf:type nor wdt:P279.
If you have a look at the entity of the capital and city state Berlin, you can see that there is information about "instance of", but this property is supposed to be https://www.wikidata.org/wiki/Property:P31. And none of them links to wd:Q515, I'm wondering from where you got this idea.
But to be honest, I don't know that much about Wikidata and to me, it's not clear why no rdf:type is used, but a common pattern for RDF datasets is to use
?s rdf:type/rdfs:subClassOf* SUPER_CLASS .
if we assume that there is rdf:type information available.
If you check the types wd:Q64 is an instance of
SELECT DISTINCT ?type ?typeLabel WHERE {
wd:Q64 (a | wdt:P31) ?type.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?item
None of them are City (wd:Q515) or a sub-class of it.
Looks like a data issue. Perhaps you should contact Wikidata.