Solution examples 2023: Difference between revisions

From info216
Line 85: Line 85:


==Task 3: RDFS rules and OWL expressions==
==Task 3: RDFS rules and OWL expressions==
'''RDFS rules'''


Question 61:
Question 61:
Line 112: Line 114:




*** OWL axioms
'''OWL axioms'''


Question 66:
Question 66:
Line 145: Line 147:




*** SPARQL queries
==Task 4: SPARQL queries==


Question 70:
Count the number of movies that are represented in the graph.
Count the number of movies that are represented in the graph.


<pre>
SELECT (COUNT(?movie) AS ?count) WHERE {
SELECT (COUNT(?movie) AS ?count) WHERE {
     ?movie rdf:type :Movie
     ?movie rdf:type :Movie
}
}
</pre>


Question 71:
List the titles and years of all movies.
List the titles and years of all movies.


<pre>
SELECT ?title ?year WHERE {
SELECT ?title ?year WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 160: Line 167:
         dc:year ?year  
         dc:year ?year  
}
}
</pre>


Question 72:
List the titles and years of all movies since 2000.
List the titles and years of all movies since 2000.


<pre>
SELECT ?title ?year WHERE {
SELECT ?title ?year WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 169: Line 179:
     FILTER (INTEGER(?year) >= 2000)
     FILTER (INTEGER(?year) >= 2000)
}
}
</pre>


or:
<pre>
SELECT ?title ?year WHERE {
SELECT ?title ?year WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 176: Line 189:
     FILTER (?year >= "2000"^^xsd:year)
     FILTER (?year >= "2000"^^xsd:year)
}
}
</pre>


Question 73:
List the titles and years of all movies sorted first by year, then by name.
List the titles and years of all movies sorted first by year, then by name.


<pre>
SELECT ?title ?year WHERE {
SELECT ?title ?year WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 185: Line 201:
}
}
ORDER BY ?year, ?name
ORDER BY ?year, ?name
</pre>


Question 74:
Count the number of movies for each year with more than one movie.
Count the number of movies for each year with more than one movie.


<pre>
SELECT ?year (COUNT(?movie) AS ?count) WHERE {
SELECT ?year (COUNT(?movie) AS ?count) WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 194: Line 213:
GROUP BY ?year
GROUP BY ?year
HAVING ?count > 1
HAVING ?count > 1
</pre>


Question 75:
List the names of all persons that are both directors and actors.
List the names of all persons that are both directors and actors.


<pre>
SELECT ?name WHERE {
SELECT ?name WHERE {
     ?person (:plays_in & :director_of) / rdf:type :Movie ;
     ?person (:plays_in & :director_of) / rdf:type :Movie ;
         foaf:name ?name
         foaf:name ?name
}
}
</pre>


Question 76:
List the actor name and movie title for all lead roles.
List the actor name and movie title for all lead roles.


<pre>
SELECT ?name ?title WHERE {
SELECT ?name ?title WHERE {
     ?role rdf:type :LeadRole ;
     ?role rdf:type :LeadRole ;
Line 209: Line 234:
         :role_in / dc:title ?title
         :role_in / dc:title ?title
}
}
</pre>


Question 77:
List all distinct pairs of actor names that have played lead roles in the same movies.
List all distinct pairs of actor names that have played lead roles in the same movies.


<pre>
SELECT ?name1 ?name2 WHERE {
SELECT ?name1 ?name2 WHERE {
     ?movie rdf:type :Movie ;
     ?movie rdf:type :Movie ;
Line 221: Line 249:
     FILTER (STR(?name1) < STR(?name2))
     FILTER (STR(?name1) < STR(?name2))
}
}
</pre>
Question 78-79:
<br>SPARQL Update ''TBD.''





Revision as of 12:18, 6 May 2024

Task 2: RDF and SHACL

Questions 51-54:
RDF: Add triples TBD


For questions 55-60:

*** SHACL examples - includes answers to the exam questions

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . 
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . 
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . 
@prefix owl: <http://www.w3.org/2002/07/owl#> . 
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix : <http://info216.uib.no/movies/> .

Questions 55 and 56:

:DirectorShape a sh:NodeShape ;
    sh:targetClass :Director ;
    # A Director must have exactly one foaf:name of type xsd:string.
    sh:property [
        sh:path foaf:name ;
        sh:minCount 1 ;      # question 55
        sh:maxCount 1 ;      # question 55
        sh:type xsd:string   # question 56
    ] ;

Question 57:

    # A Director must be the director of at least one Movie.
    sh:property [
        sh:path :director_of ;
        sh:minCount 1 ;
        sh:class :Movie
    ] .

Question 58:

:ActorShape a sh:NodeShape ;
    sh:targetClass :Actor ;
    # If an actor is an actor in a resource, that resource must be a movie.
    sh:property [
        sh:path :actor_in ;
        sh:class :Movie
    ] ;

Question 59:

:ActorShape a sh:NodeShape ;
    sh:targetClass :Actor ;
    # If an actor plays a role that is a role in some resource, that resource must be a movie.
    sh:property [
        sh:path ( :plays_role :role_in ) ;
        sh:qualifiedValueShape [ sh:path :actor_in ] ;
        sh:class :Movie
    ] .

Question 60:

:MovieShape a sh:NodeShape ;
    sh:targetClass :Movie ;
    # A movie must be directed by at least one director or acted in by at least one actor.
    sh:or (
        [ sh:property [
            sh:path [ sh:inversePath :actor_in ] ;
            sh:minCount 1 ;
        ] ]
        [ sh:property [
            sh:path [ sh:inversePath :director_of ] ;
            sh:minCount 1 ;
        ] ] 
    ) .


Task 3: RDFS rules and OWL expressions

RDFS rules

Question 61: A resource that is a director_of something is a director.

:director_of rdfs:domain :Director .

Question 62: A resource that something else is a director_of is a movie.

:director_of rdfs:range :Movie .

Question 63: The year of something has type xsd:year.

:year rdfs:range xsd:year .

Question 64: An actor is a Person.

:Actor rdfs:subClassOf foaf:Person .

Question 65: A director is a person.

:Director rdfs:subClassOf foaf:Person .


OWL axioms

Question 66: Nothing can be both a person and a movie.

:Person owl:disjointWith :Movie .


Question 67: Nothing can be more than one of a person, a role, or a movie.

[] a owl:DisjointClass ;
    owl:disjointClasses ( :Person :Role :Movie ) .

Question 68: Something that plays in at least one Movie is an Actor.

:Actor rdfs:subClassOf [
    a owl:Restriction ;
    owl:onProperty :play_in ;
    owl:someValueFrom owl:Thing
]

Question 69: A LeadActor is an Actor that plays at least one LeadRole.

:LeadActor rdfs:subClassOf :Actor, [
    a owl:Restriction ;
    owl:onProperty :plays_role ;
    owl:someValueFrom :LeadRole .
] .


Task 4: SPARQL queries

Question 70: Count the number of movies that are represented in the graph.

SELECT (COUNT(?movie) AS ?count) WHERE {
    ?movie rdf:type :Movie
}

Question 71: List the titles and years of all movies.

SELECT ?title ?year WHERE {
    ?movie rdf:type :Movie ;
        dc:title ?title ;
        dc:year ?year 
}

Question 72: List the titles and years of all movies since 2000.

SELECT ?title ?year WHERE {
    ?movie rdf:type :Movie ;
        dc:title ?title ;
        dc:year ?year 
    FILTER (INTEGER(?year) >= 2000)
}

or:

SELECT ?title ?year WHERE {
    ?movie rdf:type :Movie ;
        dc:title ?title ;
        dc:year ?year 
    FILTER (?year >= "2000"^^xsd:year)
}

Question 73: List the titles and years of all movies sorted first by year, then by name.

SELECT ?title ?year WHERE {
    ?movie rdf:type :Movie ;
        dc:title ?title ;
        dc:year ?year 
}
ORDER BY ?year, ?name

Question 74: Count the number of movies for each year with more than one movie.

SELECT ?year (COUNT(?movie) AS ?count) WHERE {
    ?movie rdf:type :Movie ;
        dc:year ?year 
}
GROUP BY ?year
HAVING ?count > 1

Question 75: List the names of all persons that are both directors and actors.

SELECT ?name WHERE {
    ?person (:plays_in & :director_of) / rdf:type :Movie ;
        foaf:name ?name
}

Question 76: List the actor name and movie title for all lead roles.

SELECT ?name ?title WHERE {
    ?role rdf:type :LeadRole ;
        ^:plays_role / foaf:name ?name ;
        :role_in / dc:title ?title
}

Question 77: List all distinct pairs of actor names that have played lead roles in the same movies.

SELECT ?name1 ?name2 WHERE {
    ?movie rdf:type :Movie ;
        ^:?role_in ?role1, ?role2 .
    ?role1 rdf:type :LeadRole ;
        ^:plays_role / foaf:name ?name1 .
    ?role2 rdf:type :LeadRole ;
        ^:plays_role / foaf:name ?name2 .
    FILTER (STR(?name1) < STR(?name2))
}

Question 78-79:
SPARQL Update TBD.


      • Examples related to the programming task

from owlrl import DeductiveClosure, OWLRL_Semantics import pandas as pd from pyshacl import validate from rdflib import Namespace, Graph, Literal, RDF, DC, FOAF, XSD


ONTOLOGY_FILE = './movie-ontology.ttl' SHACL_FILE = './movie-shacl.ttl' DIRECTOR_FILE = './movie-director-year.csv' LEAD_ROLE_FILE = './movie-actor-lead-role.csv' OTHER_ROLE_FILE = './movie-actor-other-role.csv'

BASE_URI = 'http://example.org/' MOVIE = Namespace(BASE_URI)


def add_movie_triples(g, row):

   movie = row.to_dict()
   # example dict:
   # {'Movie': 'Pulp_Fiction', 'Director': 'Quentin_Tarantino', 'Year': 1994}
   movie_name = movie['Movie']
   director_name = movie['Director']
   movie_year = movie['Year']
   # update g with a set of triples that represent the movie and its director
   g.add((MOVIE[director_name], RDF.type, MOVIE.Director))
   g.add((MOVIE[director_name], FOAF.name, Literal(director_name)))
   g.add((MOVIE[director_name], MOVIE.director_of, MOVIE[movie_name]))
   g.add((MOVIE[movie_name], RDF.type, MOVIE.Movie))
   g.add((MOVIE[movie_name], DC.title, Literal(movie_name)))
   g.add((MOVIE[movie_name], MOVIE.year, Literal(movie_year, datatype=XSD.year)))


def add_lead_role_triples(g, row):

   movie = row.to_dict()
   # example dict:
   # {'Movie': 'Pulp_Fiction', 'Director': 'Quentin_Tarantino', 'Year': 1994}
   movie_name = movie['Movie']
   actor_name = movie['Actor']
   role_name = movie_name+'-role-'+movie['LeadRole']
   # update g with a set of triples that represent the movie and its director
   g.add((MOVIE[actor_name], RDF.type, MOVIE.Actor))
   g.add((MOVIE[actor_name], FOAF.name, Literal(actor_name)))
   g.add((MOVIE[actor_name], MOVIE.actor_in, MOVIE[movie_name]))
   g.add((MOVIE[actor_name], MOVIE.plays_role, MOVIE[role_name]))
   g.add((MOVIE[role_name], RDF.type, MOVIE.LeadRole))
   g.add((MOVIE[role_name], FOAF.name, Literal(movie['LeadRole'])))
   g.add((MOVIE[role_name], MOVIE.role_in, MOVIE[movie_name]))
   g.add((MOVIE[movie_name], RDF.type, MOVIE.Movie))


def add_other_role_triples(g, row):

   movie = row.to_dict()
   # example dict:
   # {'Movie': 'Pulp_Fiction', 'Director': 'Quentin_Tarantino', 'Year': 1994}
   movie_name = movie['Movie']
   actor_name = movie['Actor']
   role_name = movie_name+'-role-'+movie['Role']
   # update g with a set of triples that represent the movie and its director
   g.add((MOVIE[actor_name], RDF.type, MOVIE.Actor))
   g.add((MOVIE[actor_name], FOAF.name, Literal(actor_name)))
   g.add((MOVIE[actor_name], MOVIE.actor_in, MOVIE[movie_name]))
   g.add((MOVIE[actor_name], MOVIE.plays_role, MOVIE[role_name]))
   g.add((MOVIE[role_name], RDF.type, MOVIE.Role))
   g.add((MOVIE[role_name], FOAF.name, Literal(movie['Role'])))
   g.add((MOVIE[role_name], MOVIE.role_in, MOVIE[movie_name]))
   g.add((MOVIE[movie_name], RDF.type, MOVIE.Movie))


def load_movie_triples(g, fn):

   df = pd.read_csv(fn)
   df.apply(lambda row: add_movie_triples(g, row), axis=1)


def load_lead_role_triples(g, fn):

   df = pd.read_csv(fn)
   df.apply(lambda row: add_lead_role_triples(g, row), axis=1)


def load_other_role_triples(g, fn):

   df = pd.read_csv(fn)
   df.apply(lambda row: add_other_role_triples(g, row), axis=1)


g = Graph() g.bind(, MOVIE) load_movie_triples(g, DIRECTOR_FILE) load_lead_role_triples(g, LEAD_ROLE_FILE) load_other_role_triples(g, OTHER_ROLE_FILE) print(g.serialize(format='ttl'))


sg = Graph() sg.parse(SHACL_FILE, format='ttl') r = validate(g,

       shacl_graph=sg,
       # ont_graph=og,
       inference='rdfs'
   )

val, rg, rep = r print(rep)


g.parse(ONTOLOGY_FILE) DeductiveClosure(OWLRL_Semantics).expand(g)

print(g.serialize(format='ttl'))