How to retrieve the categorical details in Wikidata - sparql

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.

Related

How do I get the unit of a value from Wikidata using SPARQL?

I'm new to SPARQL and I'm trying to get the boiling points of a chemical from Wikidata. However, when I try this query on ethanol as an example, I get two numbers, one being the boiling point in Fahrenheit and the other in Celsius, but without being able to tell which is which.
I'd ideally like to filter to only return the Celsius value, but I'd also be happy if I could just get the unit for each value and then I can sort it out later (that's what I've tried so far, as a first step).
I've tried this:
SELECT
?temperature ?temperatureLabel ?unitLabel
WHERE {
wd:Q153 p:P2102 ?statement.
?statement ps:P2102 [
wikibase:quantityAmount ?temperature;
wikibase:quantityUnit ?unit;
].
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
and this:
SELECT
?temperature ?temperatureLabel ?unitLabel
WHERE {
wd:Q153 p:P2102 ?statement.
?statement ps:P2102 ?temperature.
?temperature wikibase:quantityUnit ?unit.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
...amongst other things, but receive no matching results. I've been banging my head against the wall with this for hours now, would really appreciate any help.
ps: links a statement to a simple value. For quantities, this means a value without unit, lower bound and upper bound.
To get the unit, you first need to access the value node from a statement with psv:. From the value node you can then get the unit and the amount with wikibase:quantityUnit and wikibase:quantityAmount.
SELECT ?temperature ?unitLabel WHERE {
wd:Q153 p:P2102 ?statement .
?statement psv:P2102 ?valuenode.
?valuenode wikibase:quantityAmount ?temperature.
?valuenode wikibase:quantityUnit ?unit.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

How to get *all* superclasses of a Wikidata entity with 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.

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

Getting all the children of a Wikidata item (but not instances)

For example, take these three cases:
Triangle Shirtwaist Factory fire (Q867316) : instance of (P31): disaster (Q3839081)
disaster: subclass of (P279) : occurrence (Q1190554)
occurrence (Q1190554) : subclass of: temporal entity (Q26907166)
World's Fair (Q172754) : subclass of (P279) : exhibition (Q464980)
exhibition (Q464980) : subclass of (P279) : event (Q1656682)
event (Q1656682) : subclass of (P279) : occurrence (Q1190554)
occurrence (Q1190554) : subclass of: temporal entity (Q26907166)
Peloponnesian War (Q33745) : instance of (P31): war (Q198)
war (Q198) : subclass of (P279) : occurrence (Q1190554)
occurrence (Q1190554) : subclass of: temporal entity (Q26907166)
I would like all the descendants of temporal entity stopping before the instances (Triangle Shirtwaist Factory fire, World's Fair, Peloponnesian War).
Is there a way to do this with SPARQL or the API?
If I understand you correctly you just want to get the way instances are classified on Wikidata.
So starting with the example #AKSW gave:
SELECT DISTINCT ?event_type ?event_typeLabel {
?event_type wdt:P279* wd:Q26907166
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 100
The * is a pretty expensive operation to calculate and by the time of writing Wikidata has close to 50 million items. That is why I had to add the LIMIT because I was getting time-outs without it.
Graphing it
To get a feel for the data I like to look at it in the Wikidata graph builder. Because it shows clustering so nice.
https://angryloki.github.io/wikidata-graph-builder/?property=P279&item=Q26907166&iterations=2&mode=reverse
As you can see there are already a lot of classifications after 2 iterations. So we might also already be happy with this query:
SELECT DISTINCT ?event_type ?event_typeLabel {
?event_type wdt:P279/wdt:P279 wd:Q26907166
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
Note that it only goes 2 times along the property P279. At the moment this gives me 281 items.
If you really need to traverse the tree in full you can filter out "instance of" (P31) statements using FILTER NOT EXISTS. But the problem is that that currently always runs into timeouts:
SELECT DISTINCT ?event_type ?event_typeLabel {
?event_type wdt:P279* wd:Q26907166 .
FILTER NOT EXISTS { ?event_type wdt:P31 [] }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 100
With a subquery you can limit the results from the tree, but you will get incomplete data:
SELECT ?event_type ?event_typeLabel
WHERE
{
{
SELECT DISTINCT ?event_type
WHERE
{
?event_type wdt:P279* wd:Q26907166 .
}
LIMIT 1000
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
FILTER NOT EXISTS { ?event_type wdt:P31 [] }
}

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.