Eksperimentering med Ontologi, versjon 0.2 - Utdanningsdirektoratet/Grep_SPARQL GitHub Wiki

Denne siden er en del av Ontologi for Grep
Skrevet: 28.05.2024

Ny tilnærming: Typer (owl) med stor forbokstav

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").

Bakgrunn

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:
image

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).
image
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.

URIer og Navnerom

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.

Problemet med homonymi

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:
image
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.

Mulige løsninger

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).

Stor forbokstav for Typer:

Separat Navnerom (med sti for hhv typer og egenskaper):

Omnavning av egenskaper:

Test av ontologi med stor forbokstav

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.

Konklusjon

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:

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.






For spesielt interesserte

Følgende egenskaper er homonyme med typer i Grep:

  • dokumenttype
  • fagkategori
  • fagtype
  • kompetansemaalsett
  • oppgave
  • opplaeringsfag
  • opplaeringsnivaa
  • programfag
  • sensur
  • sluttkompetanse
  • spraaknivaa
  • status

De to mest åpenbare spørringene med en ontologi

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

Spørringer i ontologi med stor forbokstav

OntologiUppercase

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.




OntologiUpperMedV201906

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 avBIND```:

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:
image
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.

Flere spørringer

Oppslag av typer og egenskaper for å lese definisjoner

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:
image

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:
image
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.




Hvilke mulige egenskaper finnes for en gitt type

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

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