Einführung in Wikidata-Query-Service

Ein möglichst einfaches Beispiel für einen Wikidata-Query ist z.B. »zeige mir alle Bundesländer von Deutschland«. Nun, Deutschland (Q183) ist Wikidata zwar bekannt, aber nicht »ist Bundesland von«. Aber es gibt P150, der etwas abstrakter gehalten ist. Im Query kommt nun ein Tripel der Form Subjekt Prädikat Objekt vor, oder auch Objekt Prädikat Subjekt, wobei Subjekt das sein soll, wonach wir suchen. Ein Fragezeichen vor einem Bezeichner sagt aus, dass dieser Bezeichner eine Variable sein soll. Man schreibt dann:

SELECT ?Subjekt WHERE {
  Objekt Prädikat ?Subjekt
}

Ein Rautezeichen leitet einen Kommentar bis zum Ende der Zeile ein. Und hier nun das Beispiel:

# Q183: Germany
# P150: contains administrative territorial entity

SELECT ?B WHERE {
  wd:Q183 wdt:P150 ?B
}

Wörtliche Übersetzung: »Wähle alle B aus für die gilt: Deutschland enthält B als administrative territoriale Einheit«. Die Ausgabe besteht aus 16 Resultaten, also offensichtlich die Bundesländer einschließlich der Stadtstaaten Berlin, Hamburg und Bremen.

Nun stehen dort nur die Datenbank-Identifizierer Q64, Q980, Q985 usw. Wir wollen stattdessen nun die Namen dieser Bundesländer wissen. Dazu muss für jeden Datenbank-Identifizierer das label extrahiert werden, was mit einer SERVICE-Anweisung geschieht. Dann kann mit SubjektLabel darauf zugegriffen werden.

SELECT ?B ?BLabel WHERE {
  wd:Q183 wdt:P150 ?B.
  SERVICE wikibase:label {
    bd:serviceParam wikibase:language "de"
  }
}

Der Punkt zwischen zwei Ausdrücken bedeutet die logische Konjunktion dieser Ausdrücke. Steht nach dem Punkt kein Ausdruck mehr, so ist der Punkt wirkungslos.

Wir wollen die Bundesländer noch alphabetisch anordnen:

SELECT ?B ?BLabel WHERE {
  # ...
} ORDER BY ?BLabel

Nun kann die Ausgabe unter anderem im JSON-Format heruntergeladen und in eigene Programme eingebunden werden. Die Daten stehen unter der Creative-Commons-Lizenz CC0.

Von jedem Bundesland würde man nun gerne die Einwohnerzahl (Population) erfahren. Dazu betrachten wir zunächst Berlin.

# Q64: Berlin
# P1082: population

SELECT ?pop WHERE {
  # Berlin hat die Population ?pop
  wd:Q64 wdt:P1082 ?pop
}

Das Ergebnis ist 3469849 (Abruf am 12. Januar 2017), das ist die Population am letzten bekannten Zeitpunkt, den 31. Dezember 2014. Problematisch ist hierbei, dass sich die Population mit der Zeit verändern kann. Man würde also auch gerne die Population zu einem bestimmten Zeitpunkt erfahren.

Zunächst gibt wird durch das Präfix wdt: immer ein Objekt ausgedrückt. Zu diesem Objekt gehört ein Anweisungsknoten, welcher durch das Präfix p: ausgedrückt wird. Zu einem Anweisungsknoten drückt das Präfix ps: (property statement) drückt eine Eigenschafts-Anweisung aus, das Präfix pq: (property qualifier) einen Qualifizierer. Der Query

SELECT ?pop ?value WHERE {
  wd:Q64 p:P1082 ?pop.
  ?pop ps:P1082 ?value
}

gibt nun eine ganze Liste von Zahlen zurück. Das ist die Population zu unterschiedlichen Zeitpunkten in der Geschichte. Nun soll eine Liste von Einträgen (Zeit, Einwohnerzahl) erstellt werden, die der Zeit nach geordnet ist.

# P585: point in time

SELECT ?time ?value WHERE {
  wd:Q64 p:P1082 ?pop.
  ?pop ps:P1082 ?value.
  ?pop pq:P585 ?time
} ORDER BY ?time

Es folgt der Query für die Liste der Einträge (Bundesland, Einwohnerzahl) nach der Einwohnerzahl geordnet.

SELECT ?BLabel ?pop WHERE {
  wd:Q183 wdt:P150 ?B.
  ?B wdt:P1082 ?pop.
  SERVICE wikibase:label {
    bd:serviceParam wikibase:language "de"
  }
} ORDER BY ?pop

Das ergab am 12. Januar 2017 aber nur 15 Resultate. Ist von einem Bundesland die Einwohnerzahl nicht bekannt, so wird es auch nicht mit in die Liste aufgenommen.

Der Zeitpunkt für die Erhebung der Einwohnerzahl soll auch mit angegeben werden.

SELECT ?BLabel ?value ?time WHERE {
  wd:Q183 wdt:P150 ?B.
  ?B p:P1082 ?pop.
  ?pop ps:P1082 ?value.
  ?pop pq:P585 ?time.
  SERVICE wikibase:label {
    bd:serviceParam wikibase:language "de"
  }
}

Hierbei wird jedoch wieder die Liste der Einwohnerzahl zu allen bekannten Zeitpunkten angegeben, was prinzipiell legitim ist, aber zu einem sehr großen Datensatz führen kann. Am 12. Januar 2017 ergab das 78 Resultate.

Mit zusätzlicher Syntax lässt sich das letzte Beispiel etwas verkürzen. Zunächst lässt sich

  ?pop ps:P1082 ?value.
  ?pop pq:P585 ?time

verkürzen zu

  ?pop ps:P1082 ?value; pq:P585 ?time

Nun lässt sich

  ?B p:P1082 ?pop.
  ?pop ps:P1082 ?value; pq:P585 ?time

weiter verkürzen zu

  ?B p:P1082 [ps:P1082 ?value; pq:P585 ?time]

Referenz

P31: instance of
P279: subclass of
P585: point in time
P577: publication date

Q11471: time
Q186408: point in time
Q7366: song

Literatur

  1. TweetsFactsAndQueries: »A Guide To WDQS«.
  2. Steve Harris (Hg.): »SPARQL 1.1 Query Language«.