SPARQL‐kurs ‐ del 1 - Utdanningsdirektoratet/Grep_SPARQL GitHub Wiki

Denne siden er en del av SPARQL-kurs

<-- Forsiden  del 2 -->

Del 1: Hva er SPARQL?

SPARQL er et spørrespråk for databaser som er av RDF-typen (Resource Description Framework (RDF)). SPARQL skiller seg fra SQL ved at spørringene er basert på en subjekt-predikat-objekt-struktur som i semantikken for språk. Derfor kalles RDF en semantisk teknologi. Navnet er et akronym for "SPARQL Protocol And RDF Query Language" (et rekursivt akronym der, altså...).

Hvis du har lyst, kan du gjerne spandere 11 minutter og 18 sekunder på Prof. Dr. Harald Sack's video "Knowledge Graphs - 1.6 The Semantic Web", som jeg synes har en bra intro til temaet. Hvis ikke, kan du bare å lese videre.

Men la oss gå tilbake til starten – det med at det skiller seg fra SQL. SQL er det spørrespråket hvor du kan gjøre spørringer i databaser som er ordnet med en eller flere tabeller (som gjerne er relatert til hverandre). Ta for eksempel denne tabellen vi kan kalle "Person" (tabellen for klassen Person):

                                                              
idNavne-post
14047512345Ola[email protected]
13057212345Kari[email protected]
Tabell for klassen Person. Den inneholder alle forekomster av typen Person

Dette er slik vi er vant til å ordne ting i Excel også, så dette er kjent. Men i RDF vil den samme informasjonen ordnes etter et semantisk prinsipp (som i språk), ved hjelp av såkalte tripler (triples). En triple består av subjekt, predikat og objekt (og i den rekkefølgen). Vi kommer nærmere tilbake til semantikken. En RDF-database blir gjerne kalt en (engelsk) "triple store", i prinsippet bare en masse linjer med tripler etter hverandre. Ikke bare tabellen over, men en hel database skrives på denne måten (i ttl-format (Turtle)):

@prefix ex: <http://eksempel.no/>
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

ex:14047512345 rdf:type ex:Person .
ex:14047512345 ex:Navn "Ola" .
ex:14047512345 ex:e-post "[email protected]" .
ex:13057212345 rdf:type ex:Person .
ex:13057212345 ex:Navn "Kari" .
ex:13057212345 ex:e-post "[email protected]" .
ex:26127912345 rdf:type ex:Sjimpanse .
ex:26127912345 ex:Navn "Julius" .

Grafen over er en triple store. Den inneholder blant annet elementer av typen Person, for du ser jeg plutselig har blandet inn en berømt sjimpanse her. Det er bare for å illustrere at alle typer elementer i databasen vår ligger i samme triple store.

I en vanlig database, ville vi hatt en egen tabell med sjimpanser, men i RDF ligger altså alt i samme lager. Derfor definerer vi hvilken type de ulike elementene er ved å proklamere det i en egen triple (ex:14047512345 rdf:type ex:Person)

Hver linje i koden over representerer altså en triple. Hver linje er et "triple pattern". Hele greia vi har skrevet, kalles "graph pattern" (kan vi si grafmønster på norsk?). Når vi kommer til dette med spørringer, kaller vi også spørringen vi kjører et grafmønster. Vi kan si at når vi kjører en spørring, så skal vi finne igjen det grafmønsteret vi skriver i grafen vi søker i.

Vi sier at "ex:13057212345" er URIen til elementet vi ser på. Det blir som et telefonnummer til elementet, og som vi må "ringe" for å kommunisere videre med.

Med andre ord – hvis vi vil hente navnet til personen som har URIen "ex:13057212345", så kan vi lage følgende spørring i SPARQL:

prefix ex: <http://eksempel.no/> # Først lager vi prefix – det kommer vi tilbake til

SELECT ?o WHERE {
   ex:13057212345 ex:Navn ?o .   # Her slår vi opp elementet
}

Som gir følgende resultat

  o
1 "Kari"

Eller hvis jeg vil liste opp alle navnene på elementene som er av typen Person:

prefix ex: <http://eksempel.no/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?navn WHERE {
   ?s rdf:type ex:Person .
   ?s ex:Navn ?navn .
}

Vi slår opp alle ?s som er av typen Person, og alle disse ?s sine Navn

Som gir:

  navn
1 "Kari"
2 "Ola"

Linjen i spørringen: ?s rdf:type ex:Person . er altså en triple som består av tre deler. Fra venstre: subjekt, predikat og objekt. ?s er en variabel vi for øyeblikket kaller "s", så i prinsippet spør vi etter alt i hele grafen som står i subjekt-plassen som har rdf:type på predikat-plassen i tillegg til ex:Person på objekt-plassen. Hele mønsteret må tilfredsstilles for at vi skal få treff. Vi vil med andre ord ikke få treff på tripler i grafen som har predikat, objekt: rdf:type ex:Sjimpanse. Vi holder oss til personer.

Som vi ser i spørringen over, utvider vi med enda et grafønster som sammen med det første må tilfredsstilles for at vi skal få treff: Vi vil i tillegg også ha ?s ex:Navn ?navn. Med andre ord – i tilleg til at vi vil at ?s skal være av typen Person, vil vi også ha ?s sitt ex:Navn ?navn. Siden det er navnene er det vi er ute etter, binder vi alle ?s ex:Navn til variabelen vi kaller ?navn. Til slutt – vi ønsker kanskje ikke å vise ?s i resultat-tabellen, bare navnene. Da skriver vi SELECT ?navn øverst i spørringen. Om vi derimot ønsker å vise alle variablene i resultatet, skriver vi SELECT *

Om vi skulle ønske å vise hele den store grafen, kan vi skrive en spørring slik:

SELECT * WHERE {
   ?s ?p ?o
}

Da ville vi i vårt tilfelle fått dette resultatet:

s p o
1 ex:14047512345 rdf:type Person
2 ex:14047512345 ex:Navn "Ola"
3 ex:14047512345 ex:e-post "[email protected]"
4 osv.. osv... til og med sjimpansen Julius

Men hva om vi vil ha én person pr. linje i resultatet? Da kan vi skrive spørringen slik:

prefix ex: <http://eksempel.no/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?personNr ?navn ?ePost WHERE {
   ?personNr rdf:type ex:Person . # sikrer at vi kun får personer *
   ?personNr ex:Navn ?navn .
   ?personNr ex:e-post ?ePost .
}

* "#", og teksten etter i den femte linja, kalles kommentar og tas ikke med i spørringen, men er måte å forklare ting

Som vil gi:

personNr navn ePost
1 ex:14047512345 "Ola" "[email protected]"
2 ex:13057212345 "Kari" "[email protected]"



SPARQL-spørringens "anatomi"

prefix

Helt øverst i noen av spørringene over, ser vi én eller flere linjer som ser slik ut:

prefix ex: <http://eksempel.no/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

så skriver vi lengre nede i spørringen, f.eks:

ex:14047512345 rdf:type ex:Person .

Forklaringen er at det vi egentlig har gjort, er å skrive tre URIer, nemlig disse:

<http://eksempel.no/14047512345> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://eksempel.no/Person>

Vi bare definerer øverst hva hhv. "ex:" og "rdf:" skal stå for, slik at vi ikke trenger å ta med hele starten av URIen hver gang vi skal skrive det i spørringen. Det er derfor vi i dette kurset snakker om å slå opp ting. Vi slår opp ressurser fra Internett. Nå skal det sies at at det ikke er sikkert at du får treff hvis du limer inn disse adressene i nettleseren. URIer er ikke nødvendigvis URLer (der "L" står for "Locator"). Vi bruker URIer til globalt unike identifikatorer. Men du får treff i grafen, og det er det som er selve meningen.

URI står for "Uniform Resource Identifier", og er en viktig ingrediens når vi snakker om RDF. Hele poenget med RDF, er at databasen er på nettet, og at vi kan referere til ting ved hjelp av disse identifikatorene som er globalt unike. På den måten blir en "triplestore" som er tilgjengelig og søkbar via SPARQL, en del av et globalt nettverk av data.

Dette er kongstanken til oppfinneren av World Wide Web (www), Tim Berners-Lee. Det holder ikke med et nettverk av dokumenter over HTTP som er lenket sammen med URLer (hypertekst-lenker), men et nettverk av data (fortsatt over HTTP) som er lenket sammen med URIer. Dette kalles "Linked Data" (ofte kalt LOD, eller Linked Open Data). Jeg anbefaler å spandere et kvarter på det flammende TED-foredraget hans, der han snakker om dette.

I Greps "Workbench", som vi skal jobbe med utover i dette kurset, har vi forhåndsdefinert to prefikser for løsningen:

PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>

der vi har valgt at u: er prefiksen for typer og egenskaper, og d: er for forekomster av typer. Dette kommer vi tilbake til senere utover i kurset.

SELECT

Neste bestanddel av en SPARQL-spørring er select. Det er den delen hvor vi definerer hva vi vil ha ut i resultatet av spørringen.

select *

* gir oss alle variablene vi skriver med spørsmålstegn foran (?). Som vi har sett i eksempelsørringene over, kan vi også be om spesifikt de variablene vi vil fra spørringen som f.eks. :

select ?navn ?ePost

Hvis vi bruker Workbench'en til Grep, kan vi si at Vi lister opp hvilke variabler som skal være kolonneoverskrifter i resultat-tabellen. Det samme skjer hvis vi laster ned resultatet som .csv og importerer til Excel (noe vi prøver oss på senere i kurset).

select distinct
DISTINCT kommer vi tilbake til når vi skal gjøre søk i Grep, men vi nøyer oss nå med å bare ta med W3Cs forklaring som kanskje ikke gir så mye mening nå, og vi prøver oss forsiktig med et eksempel nedenfor. Vi kommer som sagt tilbake til det, og da tror jeg det blir klarere.

DISTINCT er en såkalt løsningsmodifikator ("solution modifier") som eliminerer dupliserte løsninger. Nærmere bestemt elimineres hver løsning som binder de samme variablene til de samme RDF-termene som andre løsninger fra løsningssettet.

Hvis ex:14047512345 hadde hatt to epostadresser:

ex:14047512345 ex:e-post "[email protected]" .
ex:14047512345 ex:e-post "[email protected]" .

og vi i spørringen bare ber om subjektet:

prefix ex: <http://eksempel.no/>

select ?s WHERE {
   ?s ex:e-post ?o
}

Spørringen sier: Gi meg alle ?s som har ex:e-post
Får vi:

s
1 ex:14047512345
2 ex:14047512345

Men setter vi DISTINCT etter SELECT:

prefix ex: <http://eksempel.no/>

select distinct ?s WHERE {
   ?s ex:e-post ?o
}

Spørringen sier: Gi meg distinkt hver ?s som har ex:e-post
Får vi:

s
1 ex:14047512345

WHERE

Det er imellom krøllparentesene i WHERE-klausulen vi skriver de graf-mønstrene vi ønsker å ta med i spørringen.

   WHERE {
   
}

Vi kommer tilbake til innmaten her.

Modifikatorer

Helt til slutt i en spørring kan vi legge til modifikatorer.

 select * where {
 ...
 }
 LIMIT 100
 ORDER BY ?ettEllerAnnet

Dette er ting som modifiserer spørringen. For eksempel kan vi si at vi kun vil ha 100 resultater (LIMIT 100), eller vi kan sortere alfabetisk etter en av variablene i spørringen (som i ORDER BY ?ettEllerAnnet).

Du kan lese om alle modifikatorene som er mulig i WIKIBOOKS' SPARQL/Modifiers, men her tar vi kun med de mest vanlige (ORDER BY, LIMIT og senere GROUP BY). Vi kommer til å bruke dem senere i kurset.

Oppsummering av anatomien

Skal vi fullt ut illustrere SPARQL-spørringens anatomi, blir det som i illustrasjonen under, men holder oss til de mest vanlige delene foreløpig:
image
Kilde: ResearchGate For eksempel ser vi at vi kan ha flere grafmønstre i et spørringsmønster ("Graph Pattern"), men i starten forholder vi oss til kun ett grafmønster i en spørring.

Oppsummering, del 1

Til nå har vi prøvd å forklare hva SPARQL er ved hjelp av noen fiktive eksempler. I del 2 skal vi gå til Greps SPARQL-tjneneste og kjøre noen innledende spørringer for gjøre oss kjent med hva vi kan finne i Grep*1, samtidig som vi repeterer og øver på spørringer som ligner på de i denne innledende delen.

<-- Forsiden  del 2 -->

*1 Grep er den nasjonale databasen for fag, læreplaner og opplæringstilbud i grunnopplæringen i Norge, og er hva denne wikien i sin helhet handler om. Denne wikien handler spesielt om vår SPARQL-tjeneste, men helt nederst på siden finner du også lenke til wikien vår som handler om Grep generelt, og REST-APIet spesielt. Alle læreplaner i Kunnskapsløftet legges inn i Grep. I tillegg finnes kodeverk og informasjon om fag i grunnskole og videregående opplæring (vgo), inkludert vurderingsordninger, samt fag- og vitnemålsmerknader til bruk i dokumentasjon av opplæringen.

Grep er ikke et eget nettsted, men en database som nettjenester og andre kan hente data fra og presentere videre for sluttbrukere. Eksempler på dette er direktoratets egne presentasjon av innholdet, og vilbli.no, som er en ekstern tjeneste. På den måten er vi vår egen datakonsument på linje med hvem som helst av våre eksterne brukere.

⚠️ **GitHub.com Fallback** ⚠️