Grundsätzlich kann die Verknüpfung von Daten auf zwei unterschiedliche Wege realisiert werden.
Die erste Möglichkeit wäre, dass in einzelnen Datensätzen Links auf einen andern Datensatz implementiert werden. In unserer Beispielapplikation hätten wir demnach in die Bibliotheksstatistik Links eingepflegt, die jede Bibliothek einem Datensatz eines Bezirks auf Geonames zugeordnet hätte. Wir haben uns gegen diese Möglichkeit entschieden, da diese Lösung mit enorm viel Handarbeit verbunden gewesen wäre. Wie das realisiert werden kann, erläutern wir in der LED Beispielsapplikation.
Die zweite Möglichkeit verknüpft die Daten ‚on the fly‘ also bei der Abfrage. In unserer Beispielapplikation nutzen wir den SPARQL-Endpoint unseres Sesame-Stores, um Suchabfragen abzusetzen, die die verschiedenen Datensätze miteinander verknüpfen. Wir suchen somit in der Bibliotheksstatistik nach den Bibliotheken, die uns interessieren und gewinnen daraus u.a. die Postleitzahl. Aus dem lokalen Datensatz der Geonames-Daten gewinnen wir zu den Postleitzahlen die Bezirksdaten. Auf diese Weise können wir mit der Abfrage z.B. die Zahl der Bibliotheken in einem Bezirk eruieren.
Die SPARQL-Abfrage zur Anzahl der Bibliotheken pro Bezirk, die im SPARQL-Endpoint unserer Beispielsapplikation (Link zum Sesame-Store einfügen) eingegeben werden kann, lautet wie folgt:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX gont: <https://gont.ch/> PREFIX owl: <http://www.w3.org/2002/07/owl#> PREFIX dbo: <http://dbpedia.org/ontology/> PREFIX lgd: <http://linkedgeodata.org/triplify/> PREFIX lgdo: <http://linkedgeodata.org/ontology/> PREFIX lgd-adress: <http://linkedgeodata.org/ontology/addr/> PREFIX lod-libraries: <http://linkeddata.fh-htwchur.ch/libraryData#> PREFIX gn: <http://www.geonames.org/ontology#> PREFIX lod-swissmaps: <http://linkeddata.fh-htwchur.ch/swissmap#>
SELECT ?district_shortName (COUNT(?district_shortName) as ?numberOfLibraries) WHERE { SERVICE <http://data.admin.ch/query> { SELECT ?muni ?muni_Version ?dbpediaSameAs ?maxgontdate ?district_shortName WHERE { # get current admission event { SELECT ?municipality_id (MAX($gontdate) AS ?maxgontdate) WHERE { ?municipality rdf:type gont:Municipality; gont:id ?municipality_id; gont:municipalityVersion ?municipalityVersion . ?municipalityVersion gont:admissionEvent ?admissionEvent . ?admissionEvent gont:date ?gontdate } GROUP BY ?municipality_id # ORDER BY DESC(?gontdate) } ?muni rdf:type gont:Municipality; gont:id ?municipality_id; owl:sameAs ?dbpediaSameAs; gont:municipalityVersion ?muni_Version . ?muni_Version gont:admissionEvent ?admi_Event; gont:district ?district . ?district gont:id ?district_id; gont:longName ?district_longName ; gont:shortName ?district_shortName . ?admi_Event gont:date ?maxgontdate . } ORDER BY ?municipality_id } SERVICE <http://dbpedia.org/sparql> { ?dbpediaSameAs dbo:postalCode ?postalcode } ?library_statDat lod-libraries:postalCode_stat ?postalcode; rdfs:label ?libstat_label } GROUP BY ?district_shortName
Und das Ergebnis stellt sich dann so dar (Auszug):
Aarau | 4 |
Affoltern | 15 |
Aigle | 7 |
Albula | 3 |
Andelfingen | 15 |
Arbon | 7 |
Arlesheim | 6 |
Baden | 6 |
Bellinzona | 3 |
Bernina | 2 |
Bern-Mittelland | 77 |
Biel/Bienne | 3 |
Bremgarten | 10 |
Brig | 3 |
Was hier in der Beschreibung einfach klingt, wäre in einer traditionellen Umgebung nur mit viel Handarbeit oder mittels Programmierung möglich. Da die Daten jetzt in RDF vorliegen und über einen SPARQL-Endpoint zur Verfügung stehen, kann das Ergebnis mit einer Abfrage ermittelt werden. Ändert sich die Fragestellung (z.B. Anzahl Bibliotheksbücher pro Kanton), kann dies mit der Veränderung der Abfrage erreicht werden.
Allerdings gilt es festzuhalten, dass die SPARQL-Abfragen selbst auch nicht zu unterschätzen sind, da diese nur korrekt formuliert werden, wenn die Struktur der Daten bekannt ist und selbst in einer Sprache abzufassen sind, die nicht leicht zu lernen ist.
Analog zur Verknüpfung der Bibliotheksstatistik mit Daten von Geonames kann das auch mit Daten von OpenStreetMap gemacht werden. So gewinnen wir beispielsweise die Adressen oder die Koordinaten der Bibliotheken.
Und schliesslich können wir von unserem SPARQL-Endpoint auch auf jeden anderen öffentlich zugänglichen SPARQL-Endpoint zugreifen und können so unsere Bibliotheksstatistikdaten auch mit andern Daten in Verbindung bringen. Mit einer federated query können wir nun beispielsweise ermitteln, auf wie viele Einwohner in einem Bezirk eine Bibliothek kommt. Diese Abfrage wäre allerdings sehr komplex. Wir wählen daher einen einfacheren Weg. Wir suchen nach der Anzahl Bibliotheken pro Bezirk einerseits und nach Anzahl Einwohner pro Bezirk. Erst im Anschluss daran verrechnen wir die beiden Ergebnisse.
Die Abfrage nach den Einwohnern pro Bezirk lautet:
PREFIX skos: <http://www.w3.org/2004/02/skos/core#> PREFIX bfs: <http://data.admin.ch/bfs/property/> PREFIX qb: <http://purl.org/linked-data/cube#> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX gont: <https://gont.ch/> PREFIX bfsclass: <http://data.admin.ch/bfs/class/2011.2/> PREFIX purlterms: <http://purl.org/dc/terms/>
SELECT ?district_shortName SUM(?allnumber) AS ?district_number_persons WHERE { { SELECT max(?gontdate) ?district ?district_longName ?district_shortName ?district_id ?munistat_label ?allnumber { ?municipalityVersion gont:admissionEvent ?admissionEvent; gont:district ?district . ?admissionEvent gont:date ?gontdate . ?district gont:longName ?district_longName ; gont:shortName ?district_shortName ; gont:id ?district_id . ?muni_district a gont:Municipality; gont:municipalityVersion ?municipalityVersion; gont:id ?munidistrict_id . ?muni_stat skos:notation ?munistat_id; skos:prefLabel ?munistat_label . { SELECT (SUM(?number) AS ?allnumber) ?muni_stat WHERE { ?s <http://data.admin.ch/bfs/property/NB_PERSON> ?number; <http://data.admin.ch/bfs/property/REPORTINGMUNICIPALITYID> ?muni_stat; <http://data.admin.ch/bfs/property/POPULATIONTYPE> ?ptype; <http://data.admin.ch/bfs/property/HISTREPORTINGMUNICIPALITYID> ?muniuri. ?ptype <http://www.w3.org/2004/02/skos/core#notation> ?pnumber. FILTER ((xsd:int(?pnumber)) <= 2) } GROUP BY ?muni_stat } Filter (xsd:integer(?munistat_id) = ?munidistrict_id) } ORDER BY ?district_shortName } } GROUP BY ?district_shortName
Und das Ergebnis stellt sich dann so dar (Auszug):
Aarau | 75'138 |
Affoltern | 51'541 |
Aigle | 43'674 |
Albula | 8'177 |
Andelfingen | 30'837 |
Arbon | 54'281 |
Arlesheim | 152'563 |
Baden | 140'061 |
Bellinzona | 50'803 |
Bernina | 4'652 |
Bern-Mittelland | 402'520 |
Biel/Bienne | 97'928 |
Bremgarten | 74'567 |
Brig | 26'303 |
Nun können wir die beiden Ergebnisse miteinander verrechnen.
Im SPARQL-Endpoint können Sie die vorbereitete SPARQL-Abfrage (federated query) zur Ermittlung der Anzahl Bibliotheken pro Bezirk ausführen. Den Bibliotheksdaten aus OpenStreetMap wird die jeweilige Postleitzahl entnommen und in den Linked Data Sets des Bundesamtes für Statistik wird über die Postleitzahl die Zugehörigkeit zum Bezirk ermittelt; schliesslich werden die zum gleichen Bezirk gehörenden Bibliotheken aufsummiert.