SPARQL‐kurs ‐ del 3 - Utdanningsdirektoratet/Grep_SPARQL GitHub Wiki
Denne siden er en del av SPARQL-kurs
Kjør først denne spørringen:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select * where {
d:aarstrinn10 u:tittel ?tittel ;
u:kortform ?kortform .
}
Da får vi et veldig rart resultat – vi får 9 resultater med kombinasjoner av tittel og kortform med de ulike språk-taggene. Hver rad er sanne, simpelt hen fordi det for eksempel er sant at d:aarstrinn10
har en tittel på nynorsk og kortform på bokmål (en av radene i tabellen sier det; prøv å finne hvilken).
Vi ser altså at ?tittel
og kortform
har en krøllalfa med ulike språkkoder etter seg. For eksempel: u:tittel "Tiende årstrinn"
@default
. For det første er dette en tekststreng (fordi teksten er mellom anførselstegn), og for det andre har vi i dataene markert hvilket språk teksten er på.
Vi har diktet opp et språk vi har kalt @default i tillegg til @nob (bokmål), @nno (nynorsk) og @sme (nordsamisk). Hvis språket vi spør etter ikke finnes i triplemønsteret du har i spørringen, kan du alltid bruke @default. Det er hovedspråket som du alltid kan bruke som et fallback-språk. Da får du tekststrengen på det språket elementet er fastsatt på. Dette er særlig viktig for læreplaner og tilhørende elementer. Læreplanen kan være fastsatt på bokmål, men ikke oversatt til nynorsk. Hvis du da spør spesifikt etter nynorsk-teksten, vil du ikke få treff. Da er @default bra å ha.
Hvis vi vil vise bare ett av språkene, må vi bruke et filter i spørringen, f.eks. slik:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select * where {
d:aarstrinn10 u:tittel ?tittel ;
u:kortform ?kortform .
FILTER(LANG(?tittel)="nob")
}
Da får vi litt færre treff, fordi vi nå tvinger resultatet til kun å vise bokmålstittelen. Vi kan legge på et filter til:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select * where {
d:aarstrinn10 u:tittel ?tittel ;
u:kortform ?kortform .
FILTER(LANG(?tittel)="nob")
FILTER(LANG(?kortform)="nob")
}
Og får:
Men la oss se nærmere på filteret vi har brukt.
For det første, kaller vi på funksjonen FILTER
, og filteret vi skriver, er innenfor parentesene som her er markert med grønt.
Den grønne parentesen starter med LANG
, som indikerer at det vi vil filtrere på, er språk. RDF har sin måte å indikere at en tekststreng er på et gitt språk, nemlig ved å legge til en "@" med en språkkode etter seg.
Det finnes egne ISO-standarder for språkkoder
- ISO 639-1: Kode med to bokstaver som indikerer språk. "no" er norsk, men vi kan også bruke "nb" for bokmål og "nn" for nynorsk. Nordamisk har "se". Lule- og sørsamisk finnes ikke i ISO 639-1.
- ISO 639-2: Kode med tre bokstaver som indikerer språk. "nor" er norsk, men vi kan også bruke "nob" for bokmål og "nno" for nynorsk. Nordsamisk har "sme", lulesamisk har "smj" og sørsamisk har "sma".
I Grep har vi valgt å bruke ISO 639-2 fordi vi har innhold på alle de tre nevnte samiske språkene. Vi bruker ikke "macrolanguage"-koden "nor", men hhv "nob" for bokmål og "nno" for nynorsk.
I tillegg har vi "tagget" alle språkversjonerte tekststrenger med "språket" vi har gitt koden "default". Tekststrengen har da innhold, likt det språket elementet vi ser på har som hovedspråk. Ting som fagkoder, årstrinn og annet administrativt innhold er alltid satt til bokmål, mens det er i læreplan-sfæren vi møter på problemstillingen om hvilket språk som er hovedspråk, eller som vi pleier å si – fastsatt språk. En læreplan er fastsatt som forskrift av enten Kunnskapsdepartementet eller Utdanningsdirektoratet, og da på en gitt målform (bokmål eller nynorsk) eller språk (nordsamisk). Vi er pålagt å følge 25%-regelen for representasjon av målformer i det offentlige Norge. De andre språkene læreplanen eventuelt har i tillegg, er da oversettelser av forskriften. Vi kommer tilbake til det...
Filteret i spørringen handler altså om språk (FILTER(LANG
). Så kan vi se lengre inn i parentes-hierarkiet:
"LANG"-delen har her to elementer:
(?tittel)
="nob"
Med andre ord – variabelen ?tittel
skal være av LANG "nob": LANG(?tittel)="nob"
Hvis vi i spørringen har flere filtre, kan vi i stedet for å gjenta FILTER
for hvert filter, legge på et parentes til – et parentes som rommer alle filtrene i spørringen, og hvert filter avsluttes med &&
, unntatt den siste:
Da ser spørringen slik ut:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select * where {
d:aarstrinn10 u:tittel ?tittel ;
u:kortform ?kortform .
FILTER(
(LANG(?tittel)="nob") &&
(LANG(?kortform)="nno")
)
}
Det vi gjør, er å lage en egen FILTER-blokk innenfor en ny parentes, og legger til et &&
etter hvert filter (unntatt det siste). På denne måten blir det lettere å lese spørringen, og den blir mer effektiv mot spørremotoren.
La oss si at vi også vil ha tittelen på bokmål, og kortformen på nordsamisk:
```SPARQL
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select * where {
d:aarstrinn10 u:tittel ?tittel ;
u:kortform ?kortform .
FILTER(
(LANG(?tittel)="nob") &&
(LANG(?tittel)="sme")
)
}
Da får vi ingen treff. Det er fordi hele spørre-grafen må være sann for at vi skal få noe resultat. Det er ikke sant at vi har en tittel på bokmål OG en kortform på nordsamisk.
Læreplanen d:MUS02-02
- finn nordsamisk tittel og kortform for denne ved hjelp av det du kan fra del 2 og 3.
Se fasit nederst på siden
La oss si at vi ønsker et slikt resultat:
Det er flere måter å få til dette på, men en av dem er å først lage alle de variablene vi ønsker oss i SELECT-delen, og deretter be om dem i spørringen på denne måten:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?tittelBokmaal ?kortformBokmaal ?tittelNordsamisk ?kortformNordsamisk where {
d:MUS02-02 u:tittel ?tittelBokmaal ;
u:tittel ?tittelNordsamisk ;
u:kortform ?kortformBokmaal ;
u:kortform ?kortformNordsamisk .
FILTER(
(LANG(?tittelBokmaal)="nob") &&
(LANG(?tittelNordsamisk)="sme") &&
(LANG(?kortformBokmaal)="nob") &&
(LANG(?kortformNordsamisk)="sme")
)
}
Bruk gjerne litt tid på å se nøye på hva vi faktisk ber om i selve spørringene, og se det i sammenheng med de ulike filtrene.
En annen måte å gjøre dette på, er ved å bruke en funksjon som kalles BIND
(med bl.a. BIND-IF-setninger), men det blir i en senere del.
Regex er et ganske stort felt innen programmering, så vi skal ikke prøve en gang å gi en uttømmende innføring. Vi vil her bare gi noen tips og triks som vi av erfaring kan bruke i spørringer mot Grep. Med regex kan vi f.eks. finne alle strenger som begynner eller slutter på en bokstav eller frase, eller f.eks. hoppe til det 4. tegnet (forfra eller bakfra) i en streng, og søke derfra. Dette kan være ganske nyttig i flere sammenhenger.
La oss begynne med det aller enkleste – å finne en match på en streng vi angir i regex-filteret. Vi vil finne alle ?o
som inneholder "Musihka oahppoplána sámegillii", der predikatet er u:tittel
og så avsløre hvilke subjekter dette gjelder.
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?s where {
?s u:tittel ?o
FILTER regex(str(?o), "Musihka oahppoplána sámegillii", "i")
}
Da får vi som resultat, den læreplanen vi nettopp så, d:MUS02-02.
Hva om vi forenkler strengen litt, men spør om litt mer info i spørringen, og i tillegg ber om en rekkefølge. Kan du se hva vi spør etter her?
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?s ?type ?o ?tittelBm where {
?s u:tittel ?o ;
u:tittel ?tittelBm ;
a ?type .
FILTER (
regex(str(?o), "sámegillii", "i") &&
LANG(?tittelBm)="nob"
)
} ORDER BY DESC(?type) ?s
Vi tar det trinn for trinn:
- SELECT: Vi ber om det opprinnelige subjektet (?s). Vi kunne like gjerne skrevet noe annet (?noeAnnet) siden dette er en variabel, men vi nøyer oss med ?s. Videre – ?type ?o og ?tittelBm
- WHERE:
?s u:tittel ?o
: Vi ber om alle ?o som er u:tittel for alle ?s. Videre, for alle ?s, vi ber om u:tittel igjen, men denne gangen binder vi den til variabelen ?tittelBm (fordi vi tvinger disse til å være på bokmål i filteret nedenfor). Til slutt lokker vi fram hvilken type alle ?s er (a ?type
).-
FILTER REGEX
: Vi vil ha treff på "sámegillii" i strengene i ?o, og vi bryr oss ikke om store/små bokstaver (`, "i") -
FILTER LANG
: Vi vil kun ha bokmålsvarianten av det vi har kalt ?tittelBm
-
- Modifikatorer:
ORDER BY
: vi ønsker at tabellen skal sorteres omvendt alfabetisk for ?type (DESC= descending), og deretter ?s (vanlig alfabetisk orden)
Vi får da noe sånt i retur:
- Lek deg fram med "^oahppoplána" og "oahppoplána$" (hva gjør
^
og$
for resultatet?) og andre ting. Kanskje du er nysgjerrig på om noen ord eller fraser finnes i Grep? - Du er kanskje også i stand til å begrense søket til titlene for en bestemt type? Prøv det.
- Du kan også la predikatet være en variabel, og for sikkerhets skyld, hvis det er et veldig vanlig ord, kan du jo legge til et LIMIT 100 eller LIMIT 1000 særlig hvis spørringen din har tre variabler som s-p-o
Denne øvelsen har egentlig ingen fasit, men vi har skrevet noen forslag nederst på siden.
Først slår vi opp den angitte læreplanen (d:MUS02-02
), og ber om tittelen og deretter kortformen. Så filtrerer vi på nordsamisk for tittelen og bokmål for kortformen av tittelen:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?tittel ?kortform where {
d:MUS02-02 u:tittel ?tittel ;
u:kortform ?kortform .
FILTER(
(LANG(?tittel)="sme") &&
(LANG(?kortform)="nob")
)
}
Jeg håper denne var ganske grei. Vi har nå brukt to ting vi har lært:
- Vi har slått opp et gitt element og bedt om et par egenskaper (fra del 1)
- Vi har laget to filtre for språk (fra denne delen)
Det er vel egentlig ikke noen fasit på denne øvelsen, men vi kan likevel gi noen eksempler. I den neste spørringen søkt etter strengen "oahppoplána$":
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?s ?type ?o ?tittelBm where {
?s u:tittel ?o ;
u:tittel ?tittelBm ;
a ?type .
FILTER (
regex(str(?o), "oahppoplána$", "i") &&
LANG(?tittelBm)="nob"
)
} ORDER BY DESC(?type) ?s
...og funnet ut at her gir søket treff der strengen er på slutten av tekststrengen, og at hvis vi skriver "^oahppoplána", begynnelsen.
Vi kan også begrense søket til titlene for en bestemt type, f.eks. slik:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX d: <http://psi.udir.no/kl06/>
select ?s ?type ?o ?tittelBm where {
?s a u:laereplan_lk20 ;
u:tittel ?o ;
u:tittel ?tittelBm ;
a ?type .
FILTER (
regex(str(?o), "oahppoplána$", "i") &&
LANG(?tittelBm)="nob"
)
} ORDER BY DESC(?type) ?s
Vi kan også la predikatet være en variabel:
select * where {
?s ?p ?o ;
a ?type .
FILTER (
regex(str(?o), "algoritme", "i") &&
lang(?o)="default"
)
}
ORDER BY ?s
LIMIT 100
Hvis du finner ressurser på nettet som handler om regex, så kan du prøve deg fram her. Du vil da finne at noen av dem er skrevet i en annen kontekst (utenfor SPARQL, og utenfor GrpahDB), så kanskje de ikke kan overføres direkte hit. Men hovedprinsippene i regex skal kunne fungere. Jeg vil uansett love deg at timene vil fly. Definitivt et eget kaninhull...
I denne delen har vi tatt for oss en munnfull. Det kan hende du må gå igjennom noe av dette flere ganger før det sitter. Vi har sett på
- språk, og hvordan språkversjonerte strenger er løst i SPARQL
- filtrering på språk i tekststrenger
- hvordan vi kan lage en filter-blokk for alle filtrene i spørrignen
- regex (og her har vi bare så vidt skrapt i overflaten)
Det er ganske viktig at denne delen sitter sånn noenlunde når vi nå går over i neste del. Den handler om å ha flere baller i lufta samtidig (uten at de faller ned). Alle spørringene så langt har handlet om spørringer som tar utgangspunkt i ett subjekt (én ball). Det vi skal gjøre videre er, med utgangspunkt i det første subjektet, få en ball til til å sprette opp, og kanskje enda en...