Eksperimentering med Ontologi, versjon 0.2 - Utdanningsdirektoratet/Grep_SPARQL GitHub Wiki
Denne siden er en del av Ontologi for Grep
Skrevet: 28.05.2024
Den første delen av artikkelen bygger på en ontologi der URI-endelser for typer/Classes er med liten forbokstav. Fila kan lastes ned her og implementeres i en egen løsning, og er midlertidig tilgjengelig for SPARQL-søk her (velg repoet "OntologiLowercase").
Tidligere har URI for klasser (det som i en ontologi ville vært owl:Class
) og egenskaper (det som i en ontologi ville vært owl:ObjectProperty
) eksistert i samme navnerom. Dette har skapt problemer, spesielt når typer/klasser deler navn med properties, som fører til homonymi i URIene.
Eksempel:
- Typen (
owl:Class
) "Kompetansemålsett":http://psi.udir.no/ontologi/kl06/kompetansemaalsett
- Egenskapen (
owl:ObjectProperty
) "kompetansemålsett":http://psi.udir.no/ontologi/kl06/kompetansemaalsett
(samme URI)
Dette fører til forvirring når man søker etter klasser og også får properties med samme URI.
En SPARQL-motor (som GraphDB og Virtuoso) som skal importere dette til et SPARQL-endepunkt vil også ha problemer, særlig når vi putter på egenskaper som rdfs:label
og rdfs:comment
på de homonyme egenskapene. I endepunktet "v201906" finnes det ikke noen egne egenskaper for egenskapene, og forvirringen unngås. Problemene starter når vi får en ontologi, der selve meningen er å putte på egenskaper på bl.a. egenskapene.
Spørring:
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT * WHERE {
?s a owl:Class ;
rdfs:label ?label .
FILTER (LANG(?label)="nb")
} ORDER BY ?s
Utsnitt av retur:
Denne spørringen gir flere treff enn forventet på grunn av URI-konflikter (teknisk sett får vi tripler som ikke er skrevet noe sted).
Klipp fra kildekoden (markering av "å" er ikke vår markering, men noe Visual Studio Code har for vane å gjøre)
Den eneste oppføringen med label: "kompetansemålsett (LK06)" er typen (owl:Class) kompetansemaalsett, men det som står som rdfs:comment i det som er rammet inn i rødt i forrige bilde, stammer egentlig fra det som i jsonld-fila (kildekoden) er oppført som owl:ObjectProperty.
Første versjon av Grep (2005/2006) var basert på Emnekart. I 2015 gikk vi over til et REST-basert API, men tilbyr RDF/SPARQL i tillegg (Emnekart og RDF ligger begge i skuffen "Semantisk teknologi"). En vanlig praksis helt fra starten i denne typen teknologi var å bruke menneskelesbare URIer, f.eks. http://psi.udir.no/ontologi/kl06/kompetansemaalsett, og ikke kryptiske strenger. Dette har med tiden endret seg. Vi i Grep bærer med oss denne arven på godt og vondt.
I en OWL-ontologi kan ikke egenskaper og typer ha samme URI. I Grep har vi flere sammenfall mellom owl:Class
og owl:ObjectProperty
(subclass av rdf:Property
sammen med owl:DatatypeProperty
.
Eksempel:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
select * where {
u:kompetansemaalsett ?property ?objekt
}
Som gir:
Resultatet blir f.eks. at samme URI gir to sett med rdfs:label
og rdfs:comment
, ett for hver av type og egenskap.
Ordforklaring, "OWL":
Web Ontology Language (OWL) er et standardisert språk utviklet av World Wide Web Consortium (W3C) for å definere og dele ontologier på nettet. OWL brukes til å representere rike og komplekse kunnskapsstrukturer med klare semantiske forhold mellom begreper. Det gir verktøy for å beskrive klasser, egenskaper og relasjoner i en domenespesifikk ontologi, noe som støtter avansert inferens og dataintegrasjon på tvers av systemer og applikasjoner.
En løsning må føre til at URIer for typer og egenskaper skiller lag på en eller annen måte. Nedenfor lister vi opp tre mulige løsninger (listen er ikke uttømmende, og forslag mottas med takk).
- Type: http://psi.udir.no/ontologi/kl06/Opplaeringsfag
- Egenskap: http://psi.udir.no/ontologi/kl06/opplaeringsfag
- Type: http://owl.udir.no/ontologi/kl06/classes/opplaeringsfag
- Egenskap: http://owl.udir.no/ontologi/kl06/properties/opplaeringsfag
- Egenskap:
Vi har testet to repositorier i Beta-miljøet, og har valgt det første alternativet over – det med stor forbokstav for typer:
- OntologiUppercase: Inneholder kun OWL-ontologi med stor forbokstav.
- OntologiUpperMedV201906: Inneholder OWL-ontologien sammen med dataene (v201906, pr. 2024.05.27).
Begge disse er å finne i Beta-miljøet.
Kildefil (jsonld) kan lastes ned her, og tilsvarende for data (hele Grep) kan lastes ned som dump. Hvis du vil gjenskape repoet "OntologiUpperMedV201906" må du både importere "ontologi-test_Uppercase.ttl" og dump-fila.
I disse ontologiene, har vi beholdt navnerommet http://psi.udir.no/ontologi/kl06/, men owl:Class
har stor forbokstav.
For spesielt interesserte, se eksempelspørringer mot disse ontologiene nederst på siden.
For å implementere ontologi i produksnonsmiøjøet må vi skrive om type-URIer til å ha stor forbokstav. Det kan vi ikke uten å bryte v201906-kontrakten. Vi holder derfor ontologien i Beta-miljøet i testøyemed.
Som en del av konklusjonen, drister vi oss til å liste opp noen punkter som handler om nytten av å ha en ontologi:
- Oppslag av typer og egenskaper: Gir mulighet for å lese definisjoner (forstå dataene).
- Identifisering av mulige egenskaper for en gitt type: Bidrar til klarhet og konsistens i dataene.
- Mulighet for semantisk interoperabilitet med andre ontologier ("Linked Open Data", hilsen oppfinneren av www, Tim Berners-Lee 😉)
Har du forslag til og tips rundt dette, ikke nøl med å ta kontakt.
Følgende egenskaper er homonyme med typer i Grep:
- dokumenttype
- fagkategori
- fagtype
- kompetansemaalsett
- oppgave
- opplaeringsfag
- opplaeringsnivaa
- programfag
- sensur
- sluttkompetanse
- spraaknivaa
- status
Vi starter med de to mest åpenbare spørringene for å se hele ontologien (kan kjøres i alle de tre nevnte repositoriene):
List alle typer (med labler og definisjoner):
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select * where {
?typer a owl:Class ;
rdfs:label ?label ;
rdfs:comment ?comment .
FILTER(
(LANG(?label)="nb")
&& (LANG(?comment)="nb")
)
}
ORDER BY ?typer
List alle egenskaper (med labler og definisjoner), sortert etter ObjectProperty og DatatypeProperty:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select ?s ?label ?comment ?type where {
{
?s a owl:ObjectProperty ;
rdf:type ?type
FILTER (?type = owl:ObjectProperty)
}
UNION {
?s a owl:DatatypeProperty ;
rdf:type ?type
FILTER (?type = owl:DatatypeProperty)
}
?s rdfs:label ?label ;
rdfs:comment ?comment .
FILTER(
(LANG(?label)="nb")
&& (LANG(?comment)="nb")
)
} ORDER BY DESC(?type) ?s
I et repo i GrpahDB der innholdet kun er en OWL-ontologi, og alle owl-Class har stor forbokstav som i URIen http://psi.udir.no/ontologi/kl06/Opplaeringsfag, slipper vi forvirringen med typer og klasser som har like URIer. Med dette som en regel, vil brukeren også venne seg til at en URI i ontologi-navnerommet med stor forbokstav alltid er en owl:Class.
I repoet OntologiUppercase i Beta-miljøet har vi gjort dette, og vi har mulighet til å teste hvordan dette vil fungere i praksis. Følgende spørring viser at vi kan kan hente fram hhv. u:opplaeringsfag
og u:Opplaeringsfag
uten at de er blandet i hver spørring:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
SELECT DISTINCT * where {
u:opplaeringsfag ?p ?o
}
Her ser vi at u:opplaeringsfag
er rdf:type
owl:ObjectProperty
.
Tilsvarende for u:Opplaeringsfag
:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
SELECT DISTINCT * where {
u:Opplaeringsfag ?p ?o
}
Her ser vi at u:Opplaeringsfag
er rdf:type
owl:Class
.
I repoet OntologiUpperMedV201906 ligger både ontologien (der owl:Class er skrevet med stor forbokstav) og dataene. Skulle et slikt repo være "fullkommet, burde også trippelen som definerer opplæringsfaget 'ADI2Z01' vært skrevet slik: ADI2Z01 rdf:type u:Opplaeringsfag
, men det blir som vi har vært inne på, å bryte med kontrakten (v201906). Derfor har vi bare importert dataene slik de er i produksjonsmiljøet. Her er 'ADI2Z01' skrevet slik: ADI2Z01 rdf:type u:opplaeringsfag
I spørringen nedenfor "trikser" vi litt for å omgå dette. Vi skriver om u:opplaeringsfag" til
u:Opplaeringsfagved hjelp av
BIND```:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?s ?tittel ?grepType ?owlClass ?rdfsLabel ?rdfsComment WHERE {
?s a u:opplaeringsfag;
u:tittel ?tittel ;
u:grep-type ?grepType .
# Binder slik at vi henter u:en_gitt_kode og transformerer den til u:En_gitt_kode med uppercase.
# Fra ?grepType til ?owlClass
# Krav: Den transformerte verdien skal fortsatt være en IRI
BIND(
IRI(CONCAT(
"http://psi.udir.no/ontologi/kl06/",
UCASE(SUBSTR(STRAFTER(STR(?grepType), "http://psi.udir.no/ontologi/kl06/"), 1, 1)),
SUBSTR(STRAFTER(STR(?grepType), "http://psi.udir.no/ontologi/kl06/"), 2)
)) AS ?owlClass
)
# Vi kan fortsatt bruke (hente ting fra) ?owlClass - i dette tilfellet ?rdfsLabel og rdfs:comment
?owlClass rdfs:label ?rdfsLabel ;
rdfs:comment ?rdfsComment .
FILTER (
(LANG(?rdfsLabel) = "nb")
&& (LANG(?rdfsComment) = "nb")
&& (LANG(?tittel) = "nob")
)
}
ORDER BY ?tittel
LIMIT 10
Klipp fra returen:
Her ser vi at både AKT2Z05 og AKT2Z02 (hentet fra dataene) er forekomster av typen Opplæringsfag (hentet fra ontologien)
Anekdote:
Vi kunne også laget en test der vi gjør om slik at forekomster av typene blir definert som type med stor forbokstav (som i ontologien). Det kan f.eks. gjøres ved hjelp av en spørring som løper igjennom alle tripler med?s u:grep-type ?o
, og skriver en ny trippel med?o
(binde ?o med regex stor forbokstav AS ?o2) med stor forbokstav, og deretter sletter de med liten forbokstav, men vi har ikke funnet det nødvendig siden vi allerede har fått de svarene vi er ute etter i testen så langt.
Eksempel 1: Oppslag på en gitt type:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?type ?rdfsLabel ?rdfsComment WHERE {
u:Opplaeringsfag rdfs:label ?rdfsLabel ;
rdfs:comment ?rdfsComment ;
a ?type .
FILTER (
(LANG(?rdfsLabel) = "nb")
&& (LANG(?rdfsComment) = "nb")
)
}
Retur:
Eksempel 2: Oppslag på en gitt egenskap:
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select * where {
u:opplaeringsfag rdfs:label ?rdfsLabel ;
rdfs:comment ?rdfsComment.
FILTER (
(LANG(?rdfsLabel)="nb")
&& (LANG(?rdfsLabel)="nb")
)
}
Retur:
Den eneste forskjellen på disse to spørringene, er u:Opplaeringsfag
i den første, og u:opplaeringsfag
i den andre. Videre ser vi at vi får to treff for den andre spørringen. Det er fordi vi spør om u:opplaeringsfag a ?type
, og vi ser at vi har rdf:Property
og owl:ObjectProperty
under ?type
i tabellen. owl:objectProperty er en sub-class av rdf:Property.
For å finne ut av dette i repoet 'v201906' (kun data, uten ontologi), vil dette være en svært tung spørring. Vi må da løpe igjennom alle forekomster av en gitt type, for deretter hente ut alle forekomster av egenskaper. Hvis vi vil finne ut av hvilke egenskaper som finnes for typen opplæringsfag, kunne vi selvsagt slått opp et tilfeldig opplæringsfag, men da vil vi kunne gå glipp av noen av egenskapene. For eksempel har ikke alle opplæringsfag egenskapen "merkelapper" (i jsonld, som er kilden til SAPRQL-endepunktet, sletter vi tomme egenskaper).
I en ontologi, er forholdet mellom type og egenskap definert, og spørringen er svært enkel (spørringen nedenfor tok 0,1 sek. da vi testet):
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * WHERE {
?egenskaper rdfs:domain u:Opplaeringsfag
}
Samme som over, men uten ontologi (vi går til repoet 'v201906'):
PREFIX u: <http://psi.udir.no/ontologi/kl06/>
SELECT DISTINCT ?egenskaper
WHERE {
[] a u:opplaeringsfag; # her løper vi igjennom alle opplæringsfag
?egenskaper ?o .
FILTER (!CONTAINS(STR(?egenskaper), "gyldighet-"))
}
Denne spørringen tok 0,3 sek. da vi testet. Hvis vi heller søker etter u:kompetansemaal (den med flest forekomster), tar det 0,8 sek.
Legg merke til filteret med negasjonen "!CONTAINS". Mange av predikatene i (?egenskaper) fører til ?o med blanke noder for gyldighetsinformasjon i referanseobjekter (lenke til egen artikkel som forklarer fenomenet). Disse elimineres med dette filteret.
Den første av de to siste spørringene gir 23 treff, og den siste gir 24. Det er fordi den andre spørringen løper igjennom forekomstene, og de har en egenskap som forteller hvilken type de er (rdf:type). I den første løper vi ikke igjennom forekomster av en type, kun egenskaper og om de har
rdfsdomain u:opplaeringsfag