├── .gitignore
├── Docs
├── SemWeb_jupyter_guide
│ ├── SemWeb_jupyter_guide.pdf
│ ├── SemWeb_jupyter_guide.tex
│ └── img
│ │ ├── jupyterlab.png
│ │ └── profiles.png
└── Workflow
│ ├── workflow.pdf
│ └── workflow.tex
├── Eval_semweb_tool.xlsx
├── Evaluation.ipynb
├── Notebooks
├── Jupyter-RDFify-Example.ipynb
├── README.md
├── SemWebEx0.ipynb
├── SemWebEx1.ipynb
├── SemWebEx2.ipynb
├── SemWebEx3.ipynb
├── SemWebEx4.ipynb
├── SemWebEx5.ipynb
└── SemWebEx6.ipynb
├── README.md
├── Scripts
├── moodle_nbgrader
│ ├── LICENSE
│ ├── README.md
│ ├── collect_files.py
│ └── update_gradesheet.py
└── snippets
│ └── semweb_dependencies.py
└── environment.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Latex aux
2 | *.aux
3 | *.glo
4 | *.idx
5 | *.log
6 | *.toc
7 | *.ist
8 | *.acn
9 | *.acr
10 | *.alg
11 | *.bbl
12 | *.blg
13 | *.dvi
14 | *.glg
15 | *.gls
16 | *.ilg
17 | *.ind
18 | *.lof
19 | *.lot
20 | *.maf
21 | *.mtc
22 | *.mtc1
23 | *.out
24 | *.synctex.gz
--------------------------------------------------------------------------------
/Docs/SemWeb_jupyter_guide/SemWeb_jupyter_guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SemWebNotebooks/Notebooks/1f6052ddd302957fbf54809366a5c7264aeb53de/Docs/SemWeb_jupyter_guide/SemWeb_jupyter_guide.pdf
--------------------------------------------------------------------------------
/Docs/SemWeb_jupyter_guide/SemWeb_jupyter_guide.tex:
--------------------------------------------------------------------------------
1 | \documentclass{article}
2 |
3 | \usepackage{hyperref}
4 | \usepackage{textcomp}
5 | \usepackage{xcolor}
6 | \usepackage{soul}
7 | \usepackage{graphicx}
8 |
9 | \definecolor{cmd}{RGB}{210,210,210}
10 | \newcommand{\consolecommand}[1]{
11 | \begingroup%
12 | \sethlcolor{cmd}%
13 | \hl{\texttt{#1}}%
14 | \endgroup}
15 | %\newcommand{\clickthis}[1]{\textbf{''#1''}}
16 | %\newcommand{\pathfmt}[1]{\textbf{#1}}
17 |
18 | \title{Jupyter Notebooks: Installation and Usage}
19 | \author{Semantic Web}
20 |
21 | \begin{document}
22 | \maketitle
23 | \section{Introduction}
24 | In our lecture \emph{Semantic Web}, we will use \emph{Jupyter Notebooks} as assignments. There are many different ways to edit and run jupyter notebooks and in this document we will show you two of them. The first way is to install a local notebook server. The second way is to use the \emph{RWTH JupyterHub}. In the following sections we will guide you through both processes step-by-step. In case one of these methods does not work for you, you can still try the other one.
25 |
26 |
27 | \section{Local Installation using Anaconda}
28 | If you choose to use a local notebook server, it is highly recommended to use a brand new virtual environment with the latest python version.
29 | Install \href{https://www.anaconda.com/products/individual#Downloads}{Anaconda} if you haven't already. Then create a new virtual environment with \consolecommand{conda create --name semweb}. Every time you want to use the virtual environment you have to activate it with \consolecommand{conda activate semweb}. Activate the environment if you haven't already. Then install jupyter notebook and the graphviz interface with \consolecommand{conda install -c conda-forge notebook python-graphviz ipython=7.18.1}. Change into your desired notebook directory and start the notebook server with \consolecommand{jupyter notebook}. After that command a webbrowser with the notebook interface should open. To open a notebook, just copy it into your directory and double click it in the webbrowser.
30 | % \subsection{Python}
31 | % For this lecture you will need \href{https://graphviz.org/download/}{GraphViz}. The anaconda package also contains the graphviz binaries but when using stock python you also need to install graphviz and add its binary directory to the path.
32 | % Because the activation of virtual environments with virtualenv is platform specific we will not cover it here, please consult \href{https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/}{this guide}. After activating your virtual environment, install jupyter notebook and the graphviz interface with \consolecommand{python -m pip install notebook graphviz}. Change into your desired notebook directory and start the notebook server with \consolecommand{jupyter notebook}. After that command a webbrowser with the notebook interface should open. To open a notebook, just copy it into your directory and double click it in the webbrowser.
33 | \section{Using JupyterHub}
34 | \begin{figure}[t]
35 | \centering
36 | \includegraphics[width=.8\textwidth]{img/profiles.png}
37 | \caption{Profile selection screen. Just choose Python and click start at the bottom of the page.}
38 | \label{fig:profiles}
39 | \end{figure}
40 | Visit the \href{https://jupyter.rwth-aachen.de/hub/login}{\emph{RWTH JupyterHub}}, then login with your RWTH Shibboleth credentials. You will then be presented the profile selection screen shown in \ref{fig:profiles}. Just choose the Python profile -- should be the top one -- and click the start button at the bottom of the page to continue. Your Jupyter Notebook server will then be started up, which may take some seconds. After this you will be taken to the \emph{JupyterLab} interface of your server shown in \ref{fig:jupyterlab}.
41 |
42 |
43 | To open a notebook in JupyterLab, you first need to upload it. On the left side of the screen should be a file browser. If it isn't there, click the folder icon on the top left. There are already some folders but ignore these for now as they are not important. To upload a file, either drag and drop it from a file explorer into the file browser of the JupyterLab or click the upload file button at the top of the file browser (small arrow pointing up) and then choose the assignment's notebook file (ends in .ipynb). After you uploaded the notebook you just have to double click it in the file browser to open it.
44 |
45 | \begin{figure}[b]
46 | \centering
47 | \includegraphics[width=\textwidth]{img/jupyterlab.png}
48 | \caption{JupyterLab interface. Upload a file by either dragging it into the file browser or clicking upload file. If the file browser isn't there, click the folder icon in the top left.}
49 | \label{fig:jupyterlab}
50 | \end{figure}
51 |
52 |
53 |
54 | \end{document}
--------------------------------------------------------------------------------
/Docs/SemWeb_jupyter_guide/img/jupyterlab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SemWebNotebooks/Notebooks/1f6052ddd302957fbf54809366a5c7264aeb53de/Docs/SemWeb_jupyter_guide/img/jupyterlab.png
--------------------------------------------------------------------------------
/Docs/SemWeb_jupyter_guide/img/profiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SemWebNotebooks/Notebooks/1f6052ddd302957fbf54809366a5c7264aeb53de/Docs/SemWeb_jupyter_guide/img/profiles.png
--------------------------------------------------------------------------------
/Docs/Workflow/workflow.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SemWebNotebooks/Notebooks/1f6052ddd302957fbf54809366a5c7264aeb53de/Docs/Workflow/workflow.pdf
--------------------------------------------------------------------------------
/Docs/Workflow/workflow.tex:
--------------------------------------------------------------------------------
1 | \documentclass{article}
2 |
3 | \usepackage{hyperref}
4 | \usepackage{textcomp}
5 | \usepackage{soul}
6 | \usepackage{xcolor}
7 |
8 | \definecolor{cmd}{RGB}{210,210,210}
9 | \newcommand{\consolecommand}[1]{
10 | \begingroup%
11 | \sethlcolor{cmd}%
12 | \hl{\texttt{#1}}%
13 | \endgroup}
14 | \newcommand{\clickthis}[1]{\textbf{''#1''}}
15 | \newcommand{\pathfmt}[1]{\textbf{#1}}
16 |
17 | \title{Jupyter Notebooks, Automatic Grading and Moodle Submission}
18 | \author{Lars Pieschel}
19 |
20 | \begin{document}
21 | \maketitle
22 | \section{Installation}
23 | You need a local installation of python, Anaconda with a new virtual environment is recommended. Use \consolecommand{pip install} or \consolecommand{conda install} to install the packages \consolecommand{notebook} and \consolecommand{nbgrader} (note: for \consolecommand{conda install} you need to change channel to conda-forge). If you only want to grade submissions, then you don't need the \consolecommand{notebook} package.
24 | \section{Creating Assignments with Formgrader}
25 | Choose a folder and execute the command \consolecommand{jupyter notebook}. This will start a notebook server and open a browser with the link to the server. After this click on the \clickthis{Formgrader} tab to open the formgrader interface. Click on \clickthis{Add new assignment} and enter an assignment name. Then click the name in the list of assignments to open up the assignment folder in jupyter notebook. Here create a new notebook and open it. To make metadata editing easier, click on \clickthis{View$\rightarrow$Cell Toolbar$\rightarrow$Create Assignment}. This will add a small dropdown to every cell with which you can choose the cell type for nbgrader. There are five cell types. \clickthis{Manually graded answer} and \clickthis{Manually graded task} are not interesting for us. \clickthis{Read-only} can't be edited by students. \clickthis{Autograder answer} are cells in which a task is given and \clickthis{Autograder tests} are cells for unittests for the task cells. Write code snippets in a autograder answer cell and surround the part that the student should write with two comments ''\#\#\# BEGIN SOLUTION'' and ''\#\#\# END SOLUTION''. For autograder tests use assertions to test the solution. Tests are by default visible for students. If you want to hide tests from the students then you have to surround the tests with two comments ''\#\#\# BEGIN HIDDEN TESTS'' and ''\#\#\# END HIDDEN TESTS''. Don't forget to set the amount of points a test cell gives when it doesn't fail.
26 |
27 | When you are finished editing the notebook, close it and click generate in the formgrader. This will generate the student version of the assignment in the folder \pathfmt{/release/}.
28 | \section{Distributing Notebooks via Moodle}
29 | Create a new assignment, enter a name and upload the student version of the assignment notebook. Under \clickthis{Feedback types} check the boxes \clickthis{Offline grading worksheet} and \clickthis{Feedback files}. Also change the maximum amount of points to that of the notebook.
30 | \section{Grading Notebooks}
31 | \textbf{Note: The given scripts only work when your moodle language is set to english. You can change the language in the top right.}
32 |
33 | Download the Scripts from \href{https://github.com/johnhw/moodle_nbgrader}{this repository}. In moodle select the assignment, view all submissions, reveal identities and then download all submissions and copy the zip folder to \pathfmt{/imports/\textlangle{}assignment\textrangle{}.zip} in your jupyter folder. Download the grading worksheet and do the same (\pathfmt{/imports/\textlangle{}assignment\textrangle{}.csv}). Then execute \consolecommand{python collect\_files.py \textlangle{}assignment\textrangle{} \textlangle{}workbook name\textrangle{}}. Then run \consolecommand{nbgrader autograde \textlangle{}assignment\textrangle{}} and \consolecommand{nbgrader generate\_feedback \textlangle{}assignment\textrangle{}}. Finally create a folder \pathfmt{/exports/} if it doesn't exist already and run \consolecommand{python update\_gradesheet.py \textlangle{}assignment\textrangle{}}. There should now be two files in the \pathfmt{/exports/} folder, a csv and a zip file.
34 | \section{Uploading Grades and Feedback}
35 | \textbf{Note: Uploading the gradesheet only works when your moodle language is set to english. You can change the language in the top right.}
36 |
37 | After the grading step, on the moodle submissions page, choose \clickthis{Upload grading worksheet}, choose the csv file from the exports folder and put a check in the box \clickthis{Allow updating records that have been modified more recently in Moodle than in the spreadsheet.} and submit. Then choose \clickthis{Upload multiple feedback files in a zip} and upload the zip file.
38 | \clearpage
39 | \section{Summary}
40 | \textbf{Note: Set your moodle's language to english or some steps will not work. You can change the language in the top right.}
41 | \begin{enumerate}
42 | \item Create Notebook
43 | \item Upload to moodle, check offline grading and feedback, set max points
44 | \item Download submissions, rename, put into imports
45 | \item Download grading sheet, rename, put into imports
46 | \item python collect\_files.py \textlangle{}assignment\textrangle{} \textlangle{}workbook name\textrangle{}
47 | \item nbgrader autograde \textlangle{}assignment\textrangle{}
48 | \item nbgrader generate\_feedback \textlangle{}assignment\textrangle{}
49 | \item python update\_gradesheet.py \textlangle{}assignment\textrangle{}
50 | \item Upload gradesheet csv to moodle, check overwrite box
51 | \item Upload feedback zip to moodle
52 | \end{enumerate}
53 |
54 | \section{Troubleshooting}
55 |
56 | \consolecommand{[AutogradeApp | ERROR] While processing assignment XYZ, the kernel became unresponsive and we could not interrupt it. This probably means that the students' code has an infinite loop that consumes a lot of memory or something similar. nbgrader doesn't know how to deal with this problem, so you will have to manually edit the students' code (for example, to just throw an error rather than enter an infinite loop).}
57 |
58 | When you see this error without there being an infinite loop in the notebook, it may be caused by a problem with nbconvert. Try downgrading to nbconvert version 5.6.1.
59 |
60 | \end{document}
--------------------------------------------------------------------------------
/Eval_semweb_tool.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SemWebNotebooks/Notebooks/1f6052ddd302957fbf54809366a5c7264aeb53de/Eval_semweb_tool.xlsx
--------------------------------------------------------------------------------
/Notebooks/Jupyter-RDFify-Example.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Jupyter-RDFify Example Notebook\n",
8 | "\n",
9 | "The purpose of this notebook is to introduce you to the [Jupyter-RDFfify](https://github.com/SemWebNotebooks/Jupyter-RDFify) extension and show you many of its awesome features.\n",
10 | "\n",
11 | "## Installation\n",
12 | "\n",
13 | "
\n",
14 | " If you've already installed Jupyter-RDFify and its dependencies in your environment, you can skip this step!\n",
15 | "
\n",
16 | "\n",
17 | "Install the extension by running the following cell."
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": null,
23 | "metadata": {
24 | "scrolled": true
25 | },
26 | "outputs": [],
27 | "source": [
28 | "!python -m pip install --no-input jupyter-rdfify"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "The extension requires Graphviz for graph visualization. If you've already installed Graphviz and added it to your path, you're good to go! If not, either install it and add it to your path or either add \"--display table\", \"--display raw\" or \"--display none\" to all cell with graphic output.\n",
36 | "\n",
37 | "If you've the conda package manager installed, you may also run the following cell to install the graphviz binaries."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "!conda install --yes -c conda-forge graphviz"
47 | ]
48 | },
49 | {
50 | "cell_type": "markdown",
51 | "metadata": {},
52 | "source": [
53 | "## Loading The Extension\n",
54 | "\n",
55 | "Run the following cell to load the extension. You need to do this for every session or IPython will not recognize the rdf magic commands."
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": null,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": [
64 | "%reload_ext jupyter-rdfify"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "## It's A Kind Of Magic\n",
72 | "\n",
73 | "Magic commands are the way to tell IPython (the Python shell that Jupyter uses) that the following line or cell is not actual python code and should thus be treated differently. Everything in Jupyter-RDFify is controlled with the same magic, which is %rdf.\n",
74 | "\n",
75 | "Please be aware that there are line and cell magics. Line magics, which only interpret the line, start with one percent sign (e.g. `%rdf`) and cell magics, which interpret both the line and the cell, start with two percent signs (e.g. `%%rdf`). The Jupyter-RDFify uses both but in some use-cases you need to use cell magics (e.g. for parsing turtle).\n",
76 | "\n",
77 | "The rdf magic is interpreted like a command line interface so you can pass additional parameters using hyphens. If at any time you are lost or want to know which parameters you can use, use the help flag (`--help`, `-h`).\n",
78 | "\n",
79 | "To see all modules:"
80 | ]
81 | },
82 | {
83 | "cell_type": "code",
84 | "execution_count": null,
85 | "metadata": {},
86 | "outputs": [],
87 | "source": [
88 | "%rdf --help"
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {},
94 | "source": [
95 | "To see the parameters of a specific module (here we show it for the turtle module):"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": [
104 | "%rdf turtle --help"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {},
110 | "source": [
111 | "## Features And Examples\n",
112 | "\n",
113 | "In the following we will present you many features that Jupyter-RDFify offers.\n",
114 | "\n",
115 | "### Serialization\n",
116 | "\n",
117 | "Jupyter-RDFify can parse many different RDF graph serializations (currently turtle, n3, json-ld and xml). After you have parsed a graph, you can later visualize, query, convert or entail it. The following cell parses a graph in Turtle notation and visualize it as a graph (this will throw an error if you do not have graphviz installed as explained in the [installation section](#Installation))."
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": null,
123 | "metadata": {},
124 | "outputs": [],
125 | "source": [
126 | "%%rdf turtle\n",
127 | "@prefix ex: .\n",
128 | "ex:Jupyter-RDFify a ex:IPythonExtension .\n",
129 | "ex:Jupyter-RDFify ex:is ex:Awesome .\n",
130 | "ex:Jupyter-RDFify ex:uses ex:Graphviz .\n",
131 | "ex:Graphviz ex:is ex:Awesome ."
132 | ]
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "metadata": {},
137 | "source": [
138 | "### Conversion\n",
139 | "\n",
140 | "You can easily convert a serialization into a different format using the `--serialize ` parameter together with the `--display raw` parameter. The following cell converts our example graph into JSON-LD."
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": null,
146 | "metadata": {},
147 | "outputs": [],
148 | "source": [
149 | "%%rdf turtle --serialize json-ld --display raw\n",
150 | "@prefix ex: .\n",
151 | "ex:Jupyter-RDFify a ex:IPythonExtension .\n",
152 | "ex:Jupyter-RDFify ex:is ex:Awesome .\n",
153 | "ex:Jupyter-RDFify ex:uses ex:Graphviz .\n",
154 | "ex:Graphviz ex:is ex:Awesome ."
155 | ]
156 | },
157 | {
158 | "cell_type": "markdown",
159 | "metadata": {},
160 | "source": [
161 | "### Querying\n",
162 | "\n",
163 | "There are two possibilities to query graphs. Either we define and query a graph locally, or we use an external endpoint.\n",
164 | "\n",
165 | "#### Local\n",
166 | "\n",
167 | "To be able to reference a local graph for querying, we need to assign it a label. We can do this using the `--label ` parameter. Lets redefine our example graph and assign it the label `awesome_graph`"
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {},
174 | "outputs": [],
175 | "source": [
176 | "%%rdf turtle --label awesome_graph\n",
177 | "\n",
178 | "@prefix ex: .\n",
179 | "\n",
180 | "ex:Jupyter-RDFify a ex:IPythonExtension .\n",
181 | "ex:Jupyter-RDFify ex:is ex:Awesome .\n",
182 | "ex:Jupyter-RDFify ex:uses ex:Graphviz .\n",
183 | "ex:Graphviz ex:is ex:Awesome ."
184 | ]
185 | },
186 | {
187 | "cell_type": "markdown",
188 | "metadata": {},
189 | "source": [
190 | "Now we can query the local graph using the SPARQL module and referencing it using `--local `."
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "execution_count": null,
196 | "metadata": {},
197 | "outputs": [],
198 | "source": [
199 | "%%rdf sparql --local awesome_graph\n",
200 | "\n",
201 | "PREFIX ex: \n",
202 | "\n",
203 | "SELECT ?result WHERE {\n",
204 | " ?result ex:is ex:Awesome .\n",
205 | "}"
206 | ]
207 | },
208 | {
209 | "cell_type": "markdown",
210 | "metadata": {},
211 | "source": [
212 | "#### External Endpoint\n",
213 | "\n",
214 | "It is also possible to query an external endpoint. As endpoints shouldn't be put under unnecessary load and as this functionality is not guaranteed to work flawlessly, we recommend using local queries instead whenever possible. You can pass an endpoint using the `--endpoint ` parameter. The following cell will query [Wikidata](https://www.wikidata.org/) for nodes of type cat and obtain their labels."
215 | ]
216 | },
217 | {
218 | "cell_type": "code",
219 | "execution_count": null,
220 | "metadata": {
221 | "scrolled": true
222 | },
223 | "outputs": [],
224 | "source": [
225 | "%%rdf sparql --endpoint \"https://query.wikidata.org/sparql\"\n",
226 | "PREFIX wdt: \n",
227 | "PREFIX wd: \n",
228 | "PREFIX bd: \n",
229 | "PREFIX wikibase: \n",
230 | "\n",
231 | "# Cats\n",
232 | "SELECT ?item ?itemLabel \n",
233 | "WHERE \n",
234 | "{\n",
235 | " ?item wdt:P31 wd:Q146.\n",
236 | " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\". }\n",
237 | "} LIMIT 10"
238 | ]
239 | },
240 | {
241 | "cell_type": "markdown",
242 | "metadata": {},
243 | "source": [
244 | "### Validation\n",
245 | "\n",
246 | "Jupyter-RDFify allows you to define graph schemas and validate your graphs with them. Currently it only supports ShEx but support for SHACL is planned.\n",
247 | "\n",
248 | "We first define our graph and our schema and assign labels `awesome_graph1` and `awesome_schema` accordingly."
249 | ]
250 | },
251 | {
252 | "cell_type": "code",
253 | "execution_count": null,
254 | "metadata": {},
255 | "outputs": [],
256 | "source": [
257 | "%%rdf turtle --label awesome_graph1\n",
258 | "\n",
259 | "PREFIX ex: \n",
260 | "\n",
261 | "ex:Jupyter-RDFify a ex:IPythonExtension .\n",
262 | "ex:Jupyter-RDFify ex:is ex:Awesome .\n",
263 | "ex:Jupyter-RDFify ex:uses ex:Graphviz .\n",
264 | "ex:Jupyter-RDFify ex:name \"Jupyter-RDFify\" .\n",
265 | "ex:Graphviz ex:is ex:Awesome ."
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "execution_count": null,
271 | "metadata": {},
272 | "outputs": [],
273 | "source": [
274 | "%%rdf shex parse --label awesome_schema\n",
275 | "\n",
276 | "PREFIX ex: \n",
277 | "PREFIX xsd: \n",
278 | "\n",
279 | "ex:AwesomeShape {\n",
280 | " ex:is [ex:Awesome];\n",
281 | " a [ex:IPythonExtension];\n",
282 | " ex:name xsd:string\n",
283 | "}"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {},
289 | "source": [
290 | "To validate your graph, use the `validate` action of the ShEx module and give the following parameters:\n",
291 | "- `--label, -l ` Label which you have assigned to the schema\n",
292 | "- `--graph, -g ` Label which you have assigned to the graph\n",
293 | "- `--start, -s ` URI of shape which is the starting point of the schema\n",
294 | "- `--focus, -f ` URI of node in graph to focus on. Can be omitted to validate all nodes.\n",
295 | "\n",
296 | "In the following we will validate our graph using our schema. The defined shape is our starting shape and we will focus on both `ex:Jupyter-RDFify` and `ex:Graphviz`. The first is expected to pass while the second is expected to be rejected with a reason."
297 | ]
298 | },
299 | {
300 | "cell_type": "code",
301 | "execution_count": null,
302 | "metadata": {
303 | "scrolled": true
304 | },
305 | "outputs": [],
306 | "source": [
307 | "%rdf shex validate --label awesome_schema --graph awesome_graph1 --start http://example.org/AwesomeShape --focus http://example.org/Jupyter-RDFify\n",
308 | "%rdf shex validate --label awesome_schema --graph awesome_graph1 --start http://example.org/AwesomeShape --focus http://example.org/Graphviz"
309 | ]
310 | },
311 | {
312 | "cell_type": "markdown",
313 | "metadata": {},
314 | "source": [
315 | "## Other Features\n",
316 | "\n",
317 | "This section will go over other features worth mentioning very quickly.\n",
318 | "\n",
319 | "### Prefixes\n",
320 | "\n",
321 | "You can predefine a prefix for most modules. This is useful for prefix declarations and similar as to not repeat them each cell. Use the `--prefix` flag to define a prefix (or the `prefix` action in case of the ShEx module)."
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": null,
327 | "metadata": {},
328 | "outputs": [],
329 | "source": [
330 | "%%rdf turtle --prefix\n",
331 | "# This prefix will be prepend to every use of the turtle module\n",
332 | "PREFIX ex: "
333 | ]
334 | },
335 | {
336 | "cell_type": "markdown",
337 | "metadata": {},
338 | "source": [
339 | "We can now define graphs without declaring the `ex:` prefix."
340 | ]
341 | },
342 | {
343 | "cell_type": "code",
344 | "execution_count": null,
345 | "metadata": {},
346 | "outputs": [],
347 | "source": [
348 | "%%rdf turtle\n",
349 | "ex:Jupyter-RDFify ex:is ex:Awesome ."
350 | ]
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {},
355 | "source": [
356 | "### Entailment\n",
357 | "\n",
358 | "Jupyter-RDFify has basic RDFS and OWL entailment functionality. This uses [OWL-RL](https://owl-rl.readthedocs.io/en/latest/) to generate a finite closure under a given semantic. As this uses a brute-force approach, it may take a long time or fail for large graphs. To entail a graph using either rdfs, owl or rdfs+owl semantics, use the `--entail ` parameter. Note that this may add some axiomatic triples as well."
359 | ]
360 | },
361 | {
362 | "cell_type": "code",
363 | "execution_count": null,
364 | "metadata": {},
365 | "outputs": [],
366 | "source": [
367 | "%%rdf turtle --entail rdfs\n",
368 | "PREFIX ex: \n",
369 | "PREFIX rdfs: \n",
370 | "\n",
371 | "ex:Jupyter-RDFify a ex:IPythonExtension .\n",
372 | "ex:IPythonExtension rdfs:subClassOf ex:Extension ."
373 | ]
374 | },
375 | {
376 | "cell_type": "markdown",
377 | "metadata": {},
378 | "source": [
379 | "### Graph Manager\n",
380 | "\n",
381 | "You can use the Graph Manager to work with already defined labelled graphs. With it, you can list, remove, draw and entail graphs. Don't forget to specify a graph with the `--label` parameter."
382 | ]
383 | },
384 | {
385 | "cell_type": "code",
386 | "execution_count": null,
387 | "metadata": {},
388 | "outputs": [],
389 | "source": [
390 | "%rdf graph --help"
391 | ]
392 | },
393 | {
394 | "cell_type": "markdown",
395 | "metadata": {},
396 | "source": [
397 | "## Accessing Underlying Data\n",
398 | "\n",
399 | "Sometimes you may want to access the underlying datastructures (RDFLib graphs, PyShEx schemas, etc.). This is useful when working with a framework like [nbgrader](https://nbgrader.readthedocs.io/) to write tests which check whether a student has given a correct solution. With the `--return-store` flag, the magic execution will return all stored data in a python dictionary."
400 | ]
401 | },
402 | {
403 | "cell_type": "code",
404 | "execution_count": 56,
405 | "metadata": {},
406 | "outputs": [
407 | {
408 | "name": "stdout",
409 | "output_type": "stream",
410 | "text": [
411 | "Possible keys:\n",
412 | " rdfgraphs\n",
413 | " rdfsources\n",
414 | " rdfresults\n",
415 | " rdfshapes\n",
416 | "Labelled graphs:\n",
417 | " awesome_graph1\n",
418 | " last\n",
419 | "Triple was found\n"
420 | ]
421 | }
422 | ],
423 | "source": [
424 | "# Obtain all data\n",
425 | "data = %rdf --return-store\n",
426 | "# Print some information\n",
427 | "print(\"Possible keys:\")\n",
428 | "for key in data:\n",
429 | " print(f\" {key}\")\n",
430 | "\n",
431 | "# Print all graph labels\n",
432 | "print(\"Labelled graphs:\")\n",
433 | "for graph in data['rdfgraphs']:\n",
434 | " print(f\" {graph}\")\n",
435 | " \n",
436 | "# Check whether the last graph contains the triple (ex:Jupyter-RDFify, rdf:type, ex:IPythonExtension)\n",
437 | "from rdflib import URIRef, RDF\n",
438 | "assert(\n",
439 | " (URIRef(\"http://example.org/Jupyter-RDFify\"), RDF.type, URIRef(\"http://example.org/IPythonExtension\"))\n",
440 | " in data['rdfgraphs']['last']\n",
441 | "), \"Triple not found\"\n",
442 | "print(\"Triple was found\")"
443 | ]
444 | }
445 | ],
446 | "metadata": {
447 | "kernelspec": {
448 | "display_name": "Python 3",
449 | "language": "python",
450 | "name": "python3"
451 | },
452 | "language_info": {
453 | "codemirror_mode": {
454 | "name": "ipython",
455 | "version": 3
456 | },
457 | "file_extension": ".py",
458 | "mimetype": "text/x-python",
459 | "name": "python",
460 | "nbconvert_exporter": "python",
461 | "pygments_lexer": "ipython3",
462 | "version": "3.8.5"
463 | }
464 | },
465 | "nbformat": 4,
466 | "nbformat_minor": 4
467 | }
468 |
--------------------------------------------------------------------------------
/Notebooks/README.md:
--------------------------------------------------------------------------------
1 | This folder contains only the **student versions** of the SemWebNotebooks, which do **not** include the unit tests used for automatic grading. Please contact `semweb [at] dbis (dot) rwth-aachen {dot} de` if you want to get a copy the full notebooks.
2 |
3 | For a nice introduction and feature overview, we recommend trying out the Jupyter-RDFify-Example.ipynb notebook. It will even guide you through the installation of Jupyter-RDFify if you haven't installed it already.
--------------------------------------------------------------------------------
/Notebooks/SemWebEx0.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "deletable": false,
7 | "editable": false,
8 | "nbgrader": {
9 | "cell_type": "markdown",
10 | "checksum": "2ff5c6a5cd4db521a0b3e454c8045fbb",
11 | "grade": false,
12 | "grade_id": "cell-af8da77aeb958933",
13 | "locked": true,
14 | "schema_version": 3,
15 | "solution": false,
16 | "task": false
17 | }
18 | },
19 | "source": [
20 | "This assignment is completely voluntary. To check if everything works, we recommend you still upload your finished notebook to moodle and let it be graded.\n",
21 | "\n",
22 | "# Introduction to Jupyter Notebooks\n",
23 | "\n",
24 | "Jupyter Notebooks are a way to combine text and interactive code execution. Every notebook consists of cells like the one you are reading right now. This is a markdown cell for text but there are also code cells like the one below this one. Code cells can be executed by selecting them and then pressing Ctrl+Enter or clicking the run button at the top. Try it with the Cell below! This should output \"Hello World!\" which will be displayed directly below the executed code cell. "
25 | ]
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": null,
30 | "metadata": {},
31 | "outputs": [],
32 | "source": [
33 | "# This is a code cell. Select it and then execute it by pressing Ctrl+Enter (Strg+Enter). Code cells are python cells by default.\n",
34 | "# If you know python try playing around with this cell. This cell will not be graded so change it to your heart's content.\n",
35 | "print(\"Hello World!\")"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {
41 | "deletable": false,
42 | "editable": false,
43 | "nbgrader": {
44 | "cell_type": "markdown",
45 | "checksum": "f2bc72ba8157dab24352cb9629915d56",
46 | "grade": false,
47 | "grade_id": "cell-eae8912ac06a2540",
48 | "locked": true,
49 | "schema_version": 3,
50 | "solution": false,
51 | "task": false
52 | }
53 | },
54 | "source": [
55 | "## Introduction to nbGrader\n",
56 | "\n",
57 | "Jupyter notebooks are great for providing instructions and incomplete code snippets which you have to complete. While working on assignments you can execute the cells as often as you want, which allows you to play around in a safe environment.\n",
58 | "\n",
59 | "But this is not all: jupyter notebooks allow for automated grading! After completing the given code snippets, you can upload your notebook file as submission to moodle. We will then autograde your submission using nbGrader. This works by executing unit tests on your code, basically checking if your code does what it should do. If a test fails, you will not get points for that task. After autograding you will get a feedback file that shows you which test failed.\n",
60 | "\n",
61 | "To give you a reference, some of the tests will be visible and executable for you. You can use this to check if your code has the correct format. But don't forget that there are also hidden tests, so just because the visible tests work does not mean your code is completely correct.\n",
62 | "\n",
63 | "### Example task\n",
64 | "\n",
65 | "Below is a code cell with incomplete python code. The task is to set variable x to 10 and variable y to 20.\n",
66 | "To set a variable in python, you just write its name, an equal sign and then a value. To set a variable z to 30, you would simply write the following:\n",
67 | "\n",
68 | "z = 30\n",
69 | "\n",
70 | "Now try to do the task in the cell below by writing your code just below the \"# YOUR SOLUTION HERE\" comment."
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": null,
76 | "metadata": {
77 | "deletable": false,
78 | "nbgrader": {
79 | "cell_type": "code",
80 | "checksum": "b9569536cc02dd637f3ab7c5b25e36f2",
81 | "grade": false,
82 | "grade_id": "cell-c7038067c95e57ed",
83 | "locked": false,
84 | "schema_version": 3,
85 | "solution": true,
86 | "task": false
87 | }
88 | },
89 | "outputs": [],
90 | "source": [
91 | "# Set x to 10 and y to 20. Don't change code that is already given.\n",
92 | "z = 30\n",
93 | "### YOUR SOLUTION HERE\n",
94 | "\n",
95 | "print(f\"x has the value {x}\")\n",
96 | "print(f\"y has the value {y}\")\n",
97 | "print(f\"z has the value {z}\")"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {
103 | "deletable": false,
104 | "editable": false,
105 | "nbgrader": {
106 | "cell_type": "markdown",
107 | "checksum": "45fbeaf701adc73642bf316d3b181226",
108 | "grade": false,
109 | "grade_id": "cell-c8bda3ca1f560670",
110 | "locked": true,
111 | "schema_version": 3,
112 | "solution": false,
113 | "task": false
114 | }
115 | },
116 | "source": [
117 | "### Example Test\n",
118 | "\n",
119 | "Below is an example test cell. These cells can not be manipulated but can be executed. This one only tests if x is set to 10 but remember that there are also hidden tests. Execute the test cell to check if your code is at least partially correct. If the cell below fails, you either have an error in your code or forgot to execute your code cell above. Try it now!"
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "execution_count": null,
125 | "metadata": {
126 | "deletable": false,
127 | "editable": false,
128 | "nbgrader": {
129 | "cell_type": "code",
130 | "checksum": "995571de091800bfd302f6c1b8cb63e5",
131 | "grade": true,
132 | "grade_id": "cell-95f7b35c0b30bb97",
133 | "locked": true,
134 | "points": 1,
135 | "schema_version": 3,
136 | "solution": false,
137 | "task": false
138 | }
139 | },
140 | "outputs": [],
141 | "source": [
142 | "assert x==10, f\"x has value {x} but should have value 10\"\n",
143 | "assert z==30, f\"z has value {z} but should have value 30. You shouldn't change code that was already given in the snippet.\"\n",
144 | "print(\"Test passed!\")"
145 | ]
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {
150 | "deletable": false,
151 | "editable": false,
152 | "nbgrader": {
153 | "cell_type": "markdown",
154 | "checksum": "cbd4c5ff53764294c9929eb4ac4a0045",
155 | "grade": false,
156 | "grade_id": "cell-3b7cab48c6f59c2b",
157 | "locked": true,
158 | "schema_version": 3,
159 | "solution": false,
160 | "task": false
161 | }
162 | },
163 | "source": [
164 | "## RDF Extension\n",
165 | "\n",
166 | "We will use an extension to execute and evaluate languages introduced in the Semantic Web lecture. The following cell will be at the top of every assignment and is used to load said extension. You need to run this cell at the start of every session. The cell below the loading cell is a very basic usage of the extension to check whether it works. Run it and it should output a graph."
167 | ]
168 | },
169 | {
170 | "cell_type": "code",
171 | "execution_count": null,
172 | "metadata": {
173 | "deletable": false,
174 | "editable": false,
175 | "nbgrader": {
176 | "cell_type": "code",
177 | "checksum": "8427196818507b8413954ef24a8154a8",
178 | "grade": false,
179 | "grade_id": "cell-9fe4e4848ca12dff",
180 | "locked": true,
181 | "schema_version": 3,
182 | "solution": false,
183 | "task": false
184 | }
185 | },
186 | "outputs": [],
187 | "source": [
188 | "%reload_ext jupyter-rdfify"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": null,
194 | "metadata": {
195 | "deletable": false,
196 | "editable": false,
197 | "nbgrader": {
198 | "cell_type": "code",
199 | "checksum": "ea2850ee041afd325eac93a404497a74",
200 | "grade": false,
201 | "grade_id": "cell-a85d3882c01ca238",
202 | "locked": true,
203 | "schema_version": 3,
204 | "solution": false,
205 | "task": false
206 | }
207 | },
208 | "outputs": [],
209 | "source": [
210 | "%%rdf turtle -d graph\n",
211 | "@prefix ex: .\n",
212 | "ex:YourInstallation ex:status ex:Works."
213 | ]
214 | },
215 | {
216 | "cell_type": "markdown",
217 | "metadata": {
218 | "deletable": false,
219 | "editable": false,
220 | "nbgrader": {
221 | "cell_type": "markdown",
222 | "checksum": "c1ee8986177e64aa0a0ef4f571c30bb6",
223 | "grade": false,
224 | "grade_id": "cell-93ea7936a38b67ca",
225 | "locked": true,
226 | "schema_version": 3,
227 | "solution": false,
228 | "task": false
229 | }
230 | },
231 | "source": [
232 | "## Submitting your assignment\n",
233 | "\n",
234 | "When you are ready to submit your assignment save the notebook and then upload it to moodle. Try doing the example task and then upload your notebook to moodle. If you did everything right, your submission will be graded and you will get feedback. Also note that all submissions are only graded once after the deadline. You can upload as many tries as you want but only the last submission will be graded."
235 | ]
236 | }
237 | ],
238 | "metadata": {
239 | "kernelspec": {
240 | "display_name": "Python 3",
241 | "language": "python",
242 | "name": "python3"
243 | },
244 | "language_info": {
245 | "codemirror_mode": {
246 | "name": "ipython",
247 | "version": 3
248 | },
249 | "file_extension": ".py",
250 | "mimetype": "text/x-python",
251 | "name": "python",
252 | "nbconvert_exporter": "python",
253 | "pygments_lexer": "ipython3",
254 | "version": "3.8.5"
255 | }
256 | },
257 | "nbformat": 4,
258 | "nbformat_minor": 4
259 | }
260 |
--------------------------------------------------------------------------------
/Notebooks/SemWebEx1.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "deletable": false,
8 | "editable": false,
9 | "nbgrader": {
10 | "cell_type": "code",
11 | "checksum": "73c565738f463863ec6757fecc9af9bf",
12 | "grade": false,
13 | "grade_id": "cell-da806457bddca4c8",
14 | "locked": true,
15 | "schema_version": 3,
16 | "solution": false,
17 | "task": false
18 | }
19 | },
20 | "outputs": [],
21 | "source": [
22 | "%reload_ext jupyter-rdfify"
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {
28 | "deletable": false,
29 | "editable": false,
30 | "nbgrader": {
31 | "cell_type": "markdown",
32 | "checksum": "747a7aa1da3e923b1e595bd9a2561c87",
33 | "grade": false,
34 | "grade_id": "cell-147e9d5d78c18ec7",
35 | "locked": true,
36 | "schema_version": 3,
37 | "solution": false,
38 | "task": false
39 | }
40 | },
41 | "source": [
42 | "**A small reminder that these assignments will be graded automatically. Please read the tasks carefully and be as pedantic as possible. Run your answers to check if your code parses correctly. Typing errors will lead to point loss. Do not change code that is already given as this may break the unit tests and lead to 0 points. Do not use comments in your code.**"
43 | ]
44 | },
45 | {
46 | "cell_type": "markdown",
47 | "metadata": {
48 | "deletable": false,
49 | "editable": false,
50 | "nbgrader": {
51 | "cell_type": "markdown",
52 | "checksum": "36191cdbb140b5ac7301deda4207ab36",
53 | "grade": false,
54 | "grade_id": "cell-baccffb6bb4a152d",
55 | "locked": true,
56 | "schema_version": 3,
57 | "solution": false,
58 | "task": false
59 | }
60 | },
61 | "source": [
62 | "# Turtle\n",
63 | "*Turtle* stands for **Terse RDF Triple Language** and is a [W3C recommended](https://www.w3.org/TR/turtle/) syntax and file format for serializing RDF Graphs. To serialize an RDF triple of the form *(Subject, Predicate, Object)* in Turtle, you just write them in that sequence, followed by a period. In this example you would write:\n",
64 | "\n",
65 | "**Subject Predicate Object .**\n",
66 | "\n",
67 | "Please note the period after a triple.\n",
68 | "\n",
69 | "In turtle, URIs are encased in angled brackets (< >). The RDF triple *(http://example.org/#Germany, http://example.org/#capital, http://example.org/#Berlin)* is serialized like this:\n",
70 | "\n",
71 | "**<http://example.org/#Germany> <http://example.org/#capital> <http://example.org/#Berlin> .**\n",
72 | "\n",
73 | "**Because of its very simple syntax, Turtle is intuitive and human-readable.**\n",
74 | "\n",
75 | "### Syntactic sugar:\n",
76 | "Because subjects or subject-predicate-combinations often repeat in the same graph, Turtle introduces some syntactic sugar.\n",
77 | "To repeat a subject, one can use a semicolon instead of a period after a triple. To express that germany has the capital Berlin and the state Bavaria, one would write the following:\n",
78 | "\n",
79 | "**<http://example.org/#Germany> <http://example.org/#capital> <http://example.org/#Berlin> ; \n",
80 | " <http://example.org/#state> <http://example.org/#Bavaria> .**\n",
81 | "\n",
82 | "To repeat a subject-predicate-combination, one can use a comma instead of a period after the triple. To express that germany has the state Berlin and the state Bavaria, one would write the following:\n",
83 | "\n",
84 | "**<http://example.org/#Germany> <http://example.org/#state> <http://example.org/#Berlin> , \n",
85 | " <http://example.org/#Bavaria> .**\n",
86 | "\n",
87 | "Both of these can be chained to repeat the same subject/subject-predicate-combination over and over.\n",
88 | "\n",
89 | "**You are allowed and even encouraged to use syntactic sugar throughout all our assignments.**\n",
90 | " "
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {
96 | "deletable": false,
97 | "editable": false,
98 | "nbgrader": {
99 | "cell_type": "markdown",
100 | "checksum": "4bd660d81b6f246a1e419d24ca0644ee",
101 | "grade": false,
102 | "grade_id": "cell-5e8f9a1e110133aa",
103 | "locked": true,
104 | "schema_version": 3,
105 | "solution": false,
106 | "task": false
107 | }
108 | },
109 | "source": [
110 | "## Task 1: My first Graph [6 points]\n",
111 | "### 1a) Sightseeing [3 points]\n",
112 | "The task is to create an RDF graph about places of interest using Turtle. The graph must contain the following Sights and their locations: The Louvre, the Colosseum and the Eiffel Tower.\n",
113 | "\n",
114 | "The graph should contain the following information: Both the **Louvre** and the **Eiffel Tower** are **located in** **France**. The **Colosseum** is **located in** **Italy**. **All** three **are sights**.\n",
115 | "\n",
116 | "Use the following URIs: \n",
117 | "The Louvre: http://example.org/sights#Louvre \n",
118 | "The Colosseum: http://example.org/sights#Colosseum \n",
119 | "The Eiffel Tower: http://example.org/sights#EiffelTower \n",
120 | "Located in: http://example.org/properties#locatedIn \n",
121 | "France: http://example.org/countries#France \n",
122 | "Italy: http://example.org/countries#Italy \n",
123 | "Sight: http://example.org/classes#Sight \n",
124 | "Is of type: http://www.w3.org/1999/02/22-rdf-syntax-ns#type\n",
125 | "\n",
126 | "**Do not use or define CURIEs (Prefixes) in this part of the task. The graph must not contain additional triples.**"
127 | ]
128 | },
129 | {
130 | "cell_type": "code",
131 | "execution_count": null,
132 | "metadata": {
133 | "deletable": false,
134 | "nbgrader": {
135 | "cell_type": "code",
136 | "checksum": "66ae973e1d9e00f6cfa1d75897aa74ac",
137 | "grade": false,
138 | "grade_id": "cell-a625a6dee09ca0d5",
139 | "locked": false,
140 | "schema_version": 3,
141 | "solution": true,
142 | "task": false
143 | }
144 | },
145 | "outputs": [],
146 | "source": [
147 | "%%rdf turtle -l sights\n",
148 | "### YOUR SOLUTION HERE"
149 | ]
150 | },
151 | {
152 | "cell_type": "markdown",
153 | "metadata": {
154 | "deletable": false,
155 | "editable": false,
156 | "nbgrader": {
157 | "cell_type": "markdown",
158 | "checksum": "8423b3ecf4767b8bddfee3a5e7341197",
159 | "grade": false,
160 | "grade_id": "cell-f3bf946883727b5f",
161 | "locked": true,
162 | "schema_version": 3,
163 | "solution": false,
164 | "task": false
165 | }
166 | },
167 | "source": [
168 | "The following cell is a test cell to check your answer. Please remember that this is only a fraction of the tests to give you an orientation and that the real evaluation is a lot more thorough."
169 | ]
170 | },
171 | {
172 | "cell_type": "code",
173 | "execution_count": null,
174 | "metadata": {
175 | "deletable": false,
176 | "editable": false,
177 | "nbgrader": {
178 | "cell_type": "code",
179 | "checksum": "5bbce85ea329cbb932a7b9181151ad2f",
180 | "grade": true,
181 | "grade_id": "cell-c927d061ef093322",
182 | "locked": true,
183 | "points": 2,
184 | "schema_version": 3,
185 | "solution": false,
186 | "task": false
187 | }
188 | },
189 | "outputs": [],
190 | "source": [
191 | "# This test will check whether your graph is complete and correct. [2 points]\n",
192 | "from rdflib import URIRef\n",
193 | "m = \"The graph is missing the following information: {}\"\n",
194 | "store = %rdf -r\n",
195 | "g = store['rdfgraphs'][\"sights\"]\n",
196 | "ex = \"http://example.org/{}\"\n",
197 | "tower = URIRef(ex.format(\"sights#EiffelTower\"))\n",
198 | "louvre = URIRef(ex.format(\"sights#Louvre\"))\n",
199 | "locIn = URIRef(ex.format(\"properties#locatedIn\"))\n",
200 | "ofType = URIRef(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\")\n",
201 | "sight = URIRef(ex.format(\"classes#Sight\"))\n",
202 | "france = URIRef(ex.format(\"countries#France\"))\n",
203 | "assert((tower, locIn, france) in g), m.format(\"The Eiffel Tower is located in France.\")\n",
204 | "assert((louvre, ofType, sight) in g), m.format(\"The Louvre is a sight.\")"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": null,
210 | "metadata": {
211 | "deletable": false,
212 | "editable": false,
213 | "nbgrader": {
214 | "cell_type": "code",
215 | "checksum": "cf9940d61fd53964206633f15b2259be",
216 | "grade": true,
217 | "grade_id": "cell-d2bfeecaca65d849",
218 | "locked": true,
219 | "points": 1,
220 | "schema_version": 3,
221 | "solution": false,
222 | "task": false
223 | }
224 | },
225 | "outputs": [],
226 | "source": [
227 | "# This test will check whether your graph is minimal (does not contain additional triples). [1 point]\n",
228 | "# This point will not be granted when you use CURIEs or define prefixes (which is forbidden in this part of the task)\n",
229 | "# Some tests - like this one - are instructor only and can't be seen/run by students."
230 | ]
231 | },
232 | {
233 | "cell_type": "markdown",
234 | "metadata": {
235 | "deletable": false,
236 | "editable": false,
237 | "nbgrader": {
238 | "cell_type": "markdown",
239 | "checksum": "cec20352d55bec9b564f2fc3bb54e2fe",
240 | "grade": false,
241 | "grade_id": "cell-af5942891348c4fb",
242 | "locked": true,
243 | "schema_version": 3,
244 | "solution": false,
245 | "task": false
246 | }
247 | },
248 | "source": [
249 | "### CURIEs\n",
250 | "Because we only used full URIs in 1a), the graph looks cluttered and both the graph and the turtle source are hard to read. But many URIs have the same prefix (http://example.org/sights for example) and turtle allows us to define abbreviations for these prefixes. These abbreviated URIs are called *Compact URIs* or *CURIES*. In Turtle, such a prefix is defined using the **@prefix** keyword, followed by the abbreviation, then the URI prefix in angled brackets (< >) and finally a period. For example, if we want to abbreviate *http://example.org/#* with *ex:*, then we need to prepend the following line to the turtle document:\n",
251 | "\n",
252 | "**@prefix ex: <http://example.org/#> .**\n",
253 | "\n",
254 | "Now we can abbreviate the RDF triple:\n",
255 | "\n",
256 | "**<http://example.org/#Germany> <http://example.org/#capital> <http://example.org/#Berlin> .**\n",
257 | "\n",
258 | "to:\n",
259 | "\n",
260 | "**ex:Germany ex:capital ex:Berlin .**\n",
261 | "\n",
262 | "Note, that we omit the angled brackets when using CURIEs.\n",
263 | "\n",
264 | "### 1b) Using CURIEs [3 points]\n",
265 | "Create the same RDF graph as in 1a) but use CURIEs and introduce the following abbreviations: \n",
266 | "Abbreviate http://example.org/sights# to **si:** \n",
267 | "Abbreviate http://example.org/countries# to **co:** \n",
268 | "Abbreviate http://example.org/properties# to **pr:** \n",
269 | "Abbreviate http://example.org/classes# to **cl:** \n",
270 | "\n",
271 | "http://www.w3.org/1999/02/22-rdf-syntax-ns# can be abbreviated to **rdf:** (optional)\n",
272 | "\n",
273 | "Because the predicate rdf:type (http://www.w3.org/1999/02/22-rdf-syntax-ns#type) is used very frequently, you can just write **a** instead of the URI. Try it! \n",
274 | "\n",
275 | "**Use the defined prefixes whenever they are applicable.** \n",
276 | "**You are allowed and even encouraged to define and use as many prefixes as you want in all following tasks and assignments.**"
277 | ]
278 | },
279 | {
280 | "cell_type": "code",
281 | "execution_count": null,
282 | "metadata": {
283 | "deletable": false,
284 | "nbgrader": {
285 | "cell_type": "code",
286 | "checksum": "5c0b1da427d39dbb7088a78c75736bc0",
287 | "grade": false,
288 | "grade_id": "cell-622f9e5d8ef2cccd",
289 | "locked": false,
290 | "schema_version": 3,
291 | "solution": true,
292 | "task": false
293 | }
294 | },
295 | "outputs": [],
296 | "source": [
297 | "%%rdf turtle -l sights2\n",
298 | "### YOUR SOLUTION HERE"
299 | ]
300 | },
301 | {
302 | "cell_type": "code",
303 | "execution_count": null,
304 | "metadata": {
305 | "deletable": false,
306 | "editable": false,
307 | "nbgrader": {
308 | "cell_type": "code",
309 | "checksum": "68e8df2519e6e8834e8676802861453e",
310 | "grade": true,
311 | "grade_id": "cell-083e36ac4704a48b",
312 | "locked": true,
313 | "points": 1,
314 | "schema_version": 3,
315 | "solution": false,
316 | "task": false
317 | }
318 | },
319 | "outputs": [],
320 | "source": [
321 | "# This test will check whether you defined all mandatory prefixes [1 point]\n",
322 | "from rdflib import URIRef\n",
323 | "store = %rdf -r\n",
324 | "g = store['rdfgraphs'][\"sights2\"]\n",
325 | "ns = list(g.namespaces())\n",
326 | "assert(('si', URIRef(\"http://example.org/sights#\")) in ns)"
327 | ]
328 | },
329 | {
330 | "cell_type": "code",
331 | "execution_count": null,
332 | "metadata": {
333 | "deletable": false,
334 | "editable": false,
335 | "nbgrader": {
336 | "cell_type": "code",
337 | "checksum": "fff9c6d94f145387b1fe46fa1ceaa3e1",
338 | "grade": true,
339 | "grade_id": "cell-cc0cb388f72d175c",
340 | "locked": true,
341 | "points": 1,
342 | "schema_version": 3,
343 | "solution": false,
344 | "task": false
345 | }
346 | },
347 | "outputs": [],
348 | "source": [
349 | "# This test will check whether you actually used CURIEs whenever applicable. [1 point]"
350 | ]
351 | },
352 | {
353 | "cell_type": "code",
354 | "execution_count": null,
355 | "metadata": {
356 | "deletable": false,
357 | "editable": false,
358 | "nbgrader": {
359 | "cell_type": "code",
360 | "checksum": "d5cb6437d567f26d2eb3e5f4c2417704",
361 | "grade": true,
362 | "grade_id": "cell-00a42b342af34ba8",
363 | "locked": true,
364 | "points": 1,
365 | "schema_version": 3,
366 | "solution": false,
367 | "task": false
368 | }
369 | },
370 | "outputs": [],
371 | "source": [
372 | "# This test will check whether the graph is complete and correct. [1 point]"
373 | ]
374 | },
375 | {
376 | "cell_type": "markdown",
377 | "metadata": {
378 | "deletable": false,
379 | "editable": false,
380 | "nbgrader": {
381 | "cell_type": "markdown",
382 | "checksum": "1e367d7fc0c413eab5975e59bab7cc91",
383 | "grade": false,
384 | "grade_id": "cell-0020acafde24d970",
385 | "locked": true,
386 | "schema_version": 3,
387 | "solution": false,
388 | "task": false
389 | }
390 | },
391 | "source": [
392 | "## Task 2: Literals [3 points]\n",
393 | "For basic values such as numbers and strings, it is impractical to use URIs. Instead of URIs we use literals. Literals have a datatype, which is string by default. Literals can only be used in the object position of triples and are encased in double quotes (\" \"). An example for a triple with a string literal is:\n",
394 | "\n",
395 | "**ex:Germany ex:name \"Deutschland\" .**\n",
396 | "\n",
397 | "To specify a *datatype*, it is appended to the literal with *two carets* (^^). A datatype can be an arbitrary URI, but there are some predefined datatypes which should suffice in most cases. These predefined datatypes use the prefix *http://www.w3.org/2001/XMLSchema#*, which is usually abbreviated with *xsd:*. An example for an integer literal:\n",
398 | "\n",
399 | "**ex:Germany ex:population \"83042235\"^^xsd:int .**\n",
400 | "\n",
401 | "There are also string literals with a specified language. This is useful for names that differ in different languages. To specify a language, we append a two character language tag with an at symbol (@) behind the literal. The literal is then automatically interpreted as a language tagged string (this datatype is never specified explicitly). To express that ex:germany has a different name in english and in german, one would add two triples:\n",
402 | "\n",
403 | "**ex:Germany ex:name \"Deutschland\"@de .** \n",
404 | "**ex:Germany ex:name \"Germany\"@en .** \n",
405 | "\n",
406 | "Please note that the URI ex:Germany is **not** the same as the literal \"Germany\" and in some cases you can't deduce the name of an entity from the URI (for example www.wikidata.org uses numerical IDs, e.g https://www.wikidata.org/entity/Q1017).\n",
407 | "\n",
408 | "### 2a) Austria [3 points]\n",
409 | "The task is to create an RDF graph about Austria with Turtle. The graph must contain the following information:\n",
410 | "\n",
411 | "Austria is called **Österreich** in german (*de*), **Austria** in english (*en*) and **Oostenrijk** in dutch (*nl*). Austria has a population of **8901064** and an area of **83878.99**km². The capital of Austria is Vienna, which is called **Vienna** in english and **Wenen** in dutch.\n",
412 | "\n",
413 | "Use the following URIs: \n",
414 | "Austria: http://example.org/countries#Austria \n",
415 | "Vienna: http://example.org/cities#Vienna \n",
416 | "Capital: http://example.org/properties#capital \n",
417 | "Area: http://example.org/properties#area \n",
418 | "Population: http://example.org/properties#population \n",
419 | "Is called: rdfs:label\n",
420 | "\n",
421 | "Language tags:\n",
422 | "\n",
423 | "| Language | Tag |\n",
424 | "| --- | --- |\n",
425 | "| English | en |\n",
426 | "| German | de |\n",
427 | "| Dutch | nl |\n",
428 | "\n",
429 | "Only use the datatypes **xsd:string**, **rdf:langString**, **xsd:int** and **xsd:float**.\n",
430 | "\n",
431 | "Tip: CURIEs do not change the graph but they make the result more readable and less error prone. Use them whenever possible!"
432 | ]
433 | },
434 | {
435 | "cell_type": "code",
436 | "execution_count": null,
437 | "metadata": {
438 | "deletable": false,
439 | "nbgrader": {
440 | "cell_type": "code",
441 | "checksum": "8c62a8376c23bfb1ea925a5792b8a3bc",
442 | "grade": false,
443 | "grade_id": "cell-3e75579d76831c23",
444 | "locked": false,
445 | "schema_version": 3,
446 | "solution": true,
447 | "task": false
448 | }
449 | },
450 | "outputs": [],
451 | "source": [
452 | "%%rdf turtle -l literals\n",
453 | "@prefix rdf: .\n",
454 | "@prefix rdfs: .\n",
455 | "@prefix xsd: .\n",
456 | "### YOUR SOLUTION HERE"
457 | ]
458 | },
459 | {
460 | "cell_type": "code",
461 | "execution_count": null,
462 | "metadata": {
463 | "deletable": false,
464 | "editable": false,
465 | "nbgrader": {
466 | "cell_type": "code",
467 | "checksum": "6397a553fe3cc0f07fd3d6a25e7c9039",
468 | "grade": true,
469 | "grade_id": "cell-ec4e45a2d27a7d3f",
470 | "locked": true,
471 | "points": 1,
472 | "schema_version": 3,
473 | "solution": false,
474 | "task": false
475 | }
476 | },
477 | "outputs": [],
478 | "source": [
479 | "# This test will check whether your graph contains the facts (even if their datatype,value or quantity is wrong). [1 point]\n",
480 | "from rdflib import URIRef\n",
481 | "store = %rdf -r\n",
482 | "g = store['rdfgraphs'][\"literals\"]\n",
483 | "ex = \"http://example.org/{}\"\n",
484 | "au = URIRef(ex.format(\"countries#Austria\"))\n",
485 | "pop = URIRef(ex.format(\"properties#population\"))\n",
486 | "vi = URIRef(ex.format(\"cities#Vienna\"))\n",
487 | "lab = URIRef(\"http://www.w3.org/2000/01/rdf-schema#label\")\n",
488 | "err = \"The graph does not contain information about {}.\"\n",
489 | "assert (au, pop, None) in g, err.format(\"Austria's population\")\n",
490 | "assert (vi, lab, None) in g, err.format(\"Vienna's name\")"
491 | ]
492 | },
493 | {
494 | "cell_type": "code",
495 | "execution_count": null,
496 | "metadata": {
497 | "deletable": false,
498 | "editable": false,
499 | "nbgrader": {
500 | "cell_type": "code",
501 | "checksum": "b79443c2944aaf80b0b6477819509040",
502 | "grade": true,
503 | "grade_id": "cell-ee0f15f19acfbd0d",
504 | "locked": true,
505 | "points": 1,
506 | "schema_version": 3,
507 | "solution": false,
508 | "task": false
509 | }
510 | },
511 | "outputs": [],
512 | "source": [
513 | "# This test will check whether your graph contains all numerical literals with correct datatypes. [1 point]"
514 | ]
515 | },
516 | {
517 | "cell_type": "code",
518 | "execution_count": null,
519 | "metadata": {
520 | "deletable": false,
521 | "editable": false,
522 | "nbgrader": {
523 | "cell_type": "code",
524 | "checksum": "b21e637e389b94cd11d86080a8021185",
525 | "grade": true,
526 | "grade_id": "cell-d8cbac1ebdcccb0f",
527 | "locked": true,
528 | "points": 1,
529 | "schema_version": 3,
530 | "solution": false,
531 | "task": false
532 | }
533 | },
534 | "outputs": [],
535 | "source": [
536 | "# This test will check whether your graph contains all language tagged literals. [1 point]"
537 | ]
538 | },
539 | {
540 | "cell_type": "markdown",
541 | "metadata": {
542 | "deletable": false,
543 | "editable": false,
544 | "nbgrader": {
545 | "cell_type": "markdown",
546 | "checksum": "0985abaabe7ae9b9c90ca5b7ccfd0c18",
547 | "grade": false,
548 | "grade_id": "cell-d95a51a59335c2de",
549 | "locked": true,
550 | "schema_version": 3,
551 | "solution": false,
552 | "task": false
553 | }
554 | },
555 | "source": [
556 | "## Task 3: Blank Nodes [3 points]\n",
557 | "Sometimes resources do not or should not have an identifier but still stand in relation to other resources. These anonymous resources are represented by blank nodes in RDF graphs. In Turtle, blank nodes are are represented with an underscore followed by a colon and an identifier (\\_:identifier). The purpose of the identifier is to be able to locally reference the anonymous resource multiple times. Even if two blank nodes in different graphs use the same identifier, they usually reference a different resource. For example, when you want to express that you know someone who is a professor but doesn't have an identifier and there is someone else you don't know who is also a professor, you do it like this:\n",
558 | "\n",
559 | "**ex:me ex:knows \\_:1 . \n",
560 | "\\_:1 rdf:type ex:professor . \n",
561 | "\\_:2 rdf:type ex:professor .**\n",
562 | "\n",
563 | "You know \\_:1 but don't know \\_:2 but they are both professors.\n",
564 | "\n",
565 | "Additionally, blank nodes are often used to represent n-ary relations. For example, a grading that needs to have a grade and a grader can be expressed like this:\n",
566 | "\n",
567 | "**ex:student ex:grading \\_:1 . \n",
568 | "\\_:1 ex:grade \"1.0\" . \n",
569 | "\\_:1 ex:grader ex:professor .**\n",
570 | "\n",
571 | "**Syntactic sugar:** \n",
572 | "To make this more readable, you can instead use square brackets (\\[ \\]) and every predicate-object-combination in between the square brackets will reference the same blank node. The grade example would then look like this:\n",
573 | "\n",
574 | "**ex:student ex:grading \\[ \n",
575 | " ex:grade \"1.0\" ; \n",
576 | " ex:grader ex:professor \n",
577 | "\\] .**\n",
578 | "\n",
579 | "Note that we must use semicolons and commas in between the brackets (see syntactic sugar at top of assignment) and there is still a period after the brackets.\n",
580 | "\n",
581 | "Also Note that the blank node identifier is exchangable as long as we use the same one when referencing the same node. That is why the bracket notation does not need an identifier.\n",
582 | "\n",
583 | "### 3a) I know someone who lives somewhere [3 points]\n",
584 | "Create an RDF graph using turtle that expresses the following: \n",
585 | "You, a person without an identifier, knows another person without an identifier, who lives at the following address:\n",
586 | "\n",
587 | "Street: Templergraben \n",
588 | "House number: 55 \n",
589 | "Postal code: 52062 \n",
590 | "City: Aachen\n",
591 | "\n",
592 | "Use the following URIs: \n",
593 | "Type: rdf:type \n",
594 | "Knows: foaf:knows \n",
595 | "Person: http://example.org/classes#Person \n",
596 | "Address: http://example.org/properties#address \n",
597 | "Street: http://example.org/properties#street \n",
598 | "House number: http://example.org/properties#houseNumber \n",
599 | "Postal code: http://example.org/properties#postalCode \n",
600 | "City: http://example.org/properties#city \n",
601 | "\n",
602 | "Hint: use an n-ary relation for the address.\n",
603 | "\n",
604 | "**Use only string literals without language tags.**"
605 | ]
606 | },
607 | {
608 | "cell_type": "code",
609 | "execution_count": null,
610 | "metadata": {
611 | "deletable": false,
612 | "nbgrader": {
613 | "cell_type": "code",
614 | "checksum": "79a506cd3eb3e91d9e2ea74a90ba5570",
615 | "grade": false,
616 | "grade_id": "cell-865f7b3dbf506688",
617 | "locked": false,
618 | "schema_version": 3,
619 | "solution": true,
620 | "task": false
621 | }
622 | },
623 | "outputs": [],
624 | "source": [
625 | "%%rdf turtle -l bnodes\n",
626 | "@prefix rdf: .\n",
627 | "@prefix foaf: .\n",
628 | "@prefix xsd: .\n",
629 | "### YOUR SOLUTION HERE"
630 | ]
631 | },
632 | {
633 | "cell_type": "code",
634 | "execution_count": null,
635 | "metadata": {
636 | "deletable": false,
637 | "editable": false,
638 | "nbgrader": {
639 | "cell_type": "code",
640 | "checksum": "215d24621daf48fb93b6f86a8239841f",
641 | "grade": true,
642 | "grade_id": "cell-c99512ff1812ee4d",
643 | "locked": true,
644 | "points": 1,
645 | "schema_version": 3,
646 | "solution": false,
647 | "task": false
648 | }
649 | },
650 | "outputs": [],
651 | "source": [
652 | "# This test will check whether there is an anonymous person that knows another anonymous person. [1 point]"
653 | ]
654 | },
655 | {
656 | "cell_type": "code",
657 | "execution_count": null,
658 | "metadata": {
659 | "deletable": false,
660 | "editable": false,
661 | "nbgrader": {
662 | "cell_type": "code",
663 | "checksum": "4fed1f72fcd8f0716d453131de412727",
664 | "grade": true,
665 | "grade_id": "cell-34bb05ce1f74e4e4",
666 | "locked": true,
667 | "points": 1,
668 | "schema_version": 3,
669 | "solution": false,
670 | "task": false
671 | }
672 | },
673 | "outputs": [],
674 | "source": [
675 | "# This test will check whether there is an anonymous entity with an n-ary address. [1 point]"
676 | ]
677 | },
678 | {
679 | "cell_type": "code",
680 | "execution_count": null,
681 | "metadata": {
682 | "deletable": false,
683 | "editable": false,
684 | "nbgrader": {
685 | "cell_type": "code",
686 | "checksum": "111a0c7bc027a0cebaf090b53c52ef58",
687 | "grade": true,
688 | "grade_id": "cell-b317826a68e2bede",
689 | "locked": true,
690 | "points": 1,
691 | "schema_version": 3,
692 | "solution": false,
693 | "task": false
694 | }
695 | },
696 | "outputs": [],
697 | "source": [
698 | "# This test will check whether there is a correct n-ary address. [1 point]"
699 | ]
700 | }
701 | ],
702 | "metadata": {
703 | "kernelspec": {
704 | "display_name": "Python 3",
705 | "language": "python",
706 | "name": "python3"
707 | },
708 | "language_info": {
709 | "codemirror_mode": {
710 | "name": "ipython",
711 | "version": 3
712 | },
713 | "file_extension": ".py",
714 | "mimetype": "text/x-python",
715 | "name": "python",
716 | "nbconvert_exporter": "python",
717 | "pygments_lexer": "ipython3",
718 | "version": "3.8.5"
719 | }
720 | },
721 | "nbformat": 4,
722 | "nbformat_minor": 4
723 | }
724 |
--------------------------------------------------------------------------------
/Notebooks/SemWebEx3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "deletable": false,
8 | "editable": false,
9 | "nbgrader": {
10 | "cell_type": "code",
11 | "checksum": "30d8b0b6ba0ed36eb04b765832aa0801",
12 | "grade": false,
13 | "grade_id": "cell-62337619e946bfb7",
14 | "locked": true,
15 | "schema_version": 3,
16 | "solution": false,
17 | "task": false
18 | }
19 | },
20 | "outputs": [],
21 | "source": [
22 | "%reload_ext jupyter-rdfify"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": null,
28 | "metadata": {
29 | "deletable": false,
30 | "editable": false,
31 | "nbgrader": {
32 | "cell_type": "code",
33 | "checksum": "6ef4f0a70d6213658c24f43d86e545ed",
34 | "grade": false,
35 | "grade_id": "cell-243b7ced18a1336a",
36 | "locked": true,
37 | "schema_version": 3,
38 | "solution": false,
39 | "task": false
40 | }
41 | },
42 | "outputs": [],
43 | "source": [
44 | "# This cell defines some helpers, imports and strings for tests. Run it!\n",
45 | "from rdflib import URIRef, BNode, Literal, XSD, RDF, RDFS\n",
46 | "ex = \"http://example.org/#\"\n",
47 | "triple = \"({}, {}, {})\"\n",
48 | "eNotContain = \"Your graph does not contain the triple:\\n{}.\"\n",
49 | "eBNode = \"The subject of the triple {} should be a blank node but it is {}\"\n",
50 | "eMultiple = \"Your graph contains multiple triples of the form {}.\"\n",
51 | "def uri(prefix, name):\n",
52 | " return URIRef(ex+name)\n",
53 | "def st(node):\n",
54 | " if isinstance(node, BNode):\n",
55 | " return \"blank node\"\n",
56 | " else:\n",
57 | " return node.n3()\n",
58 | "def containCheck(g, s, p, o):\n",
59 | " assert (s,p,o) in g, eNotContain.format(triple.format(st(s), st(p), st(o)))"
60 | ]
61 | },
62 | {
63 | "cell_type": "markdown",
64 | "metadata": {
65 | "deletable": false,
66 | "editable": false,
67 | "nbgrader": {
68 | "cell_type": "markdown",
69 | "checksum": "2a277a8140b4b03b21dc1f6a6f0c4caf",
70 | "grade": false,
71 | "grade_id": "cell-0fd22e5d0af2bcd4",
72 | "locked": true,
73 | "schema_version": 3,
74 | "solution": false,
75 | "task": false
76 | }
77 | },
78 | "source": [
79 | "The cell below defines some prefixes which you can and should use throughout the entire notebook. Run it!"
80 | ]
81 | },
82 | {
83 | "cell_type": "code",
84 | "execution_count": null,
85 | "metadata": {
86 | "deletable": false,
87 | "editable": false,
88 | "nbgrader": {
89 | "cell_type": "code",
90 | "checksum": "40db6048f17868c11eeef1a2753ac5c9",
91 | "grade": false,
92 | "grade_id": "cell-fb66abf182bcbaa9",
93 | "locked": true,
94 | "schema_version": 3,
95 | "solution": false,
96 | "task": false
97 | }
98 | },
99 | "outputs": [],
100 | "source": [
101 | "%%rdf turtle -p\n",
102 | "PREFIX rdf: \n",
103 | "PREFIX rdfs: \n",
104 | "PREFIX xsd: "
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {
110 | "deletable": false,
111 | "editable": false,
112 | "nbgrader": {
113 | "cell_type": "markdown",
114 | "checksum": "50125331d40fa1986f2818b87017da1a",
115 | "grade": false,
116 | "grade_id": "cell-1dc846c20b17545c",
117 | "locked": true,
118 | "schema_version": 3,
119 | "solution": false,
120 | "task": false
121 | }
122 | },
123 | "source": [
124 | "# Vocabularies/Ontologies and Data Modelling\n",
125 | "\n",
126 | "Up to now, all our graphs had very little meaning and could only be understood by humans. This is because we introduced new URIs for concepts and relationships (e.g. ex:capital or ex:Germany) but didn't formally describe them. This makes inferencing and finding similar or associated information difficult. To formally conceptualize our information, we need specialized vocabularies. These vocabularies called ontologies, provide terms with an agreed upon meaning together with rules and restrictions. Except some meta-ontologies, most ontologies model a specific topic and should only be used in that domain. \n",
127 | "Some problems that can be solved using such vocabularies are for example different URIs describing the same resource or a property implying another property.\n",
128 | "\n",
129 | "In this exercise we will take a look at some core ontologies and learn to write our own ontologies.\n",
130 | "\n",
131 | "## Task 1: RDF Vocabulary [4 points]\n",
132 | "\n",
133 | "RDF is not only a data model but it also defines some URIs for basic data modelling. We already learned of **rdf:type**, which is a very important property expressing the membership of an object to a specified class. But it also introduces some other properties and classes important for data modelling.\n",
134 | "\n",
135 | "### Reification\n",
136 | "\n",
137 | "Adding facts to a graph is very simple but what if we want to add a statement which may not be true? For this we need to treat a triple as an object itself. For example if the butler accuses the gardener of being the murderer, we can't just add the fact:\n",
138 | "\n",
139 | "**ex:Gardener a ex:Murderer .**\n",
140 | "\n",
141 | "as we do not know if the butler tells the truth. But we can reify this triple to make it a statement said by the butler using the properties **rdf:subject, rdf:predicate, rdf:object** and the class **rdf:Statement** which are all terms defined by RDF:\n",
142 | "\n",
143 | "**ex:Butler ex:said \\[ \n",
144 | " rdf:subject ex:Gardener ; \n",
145 | " rdf:predicate rdf:type ; \n",
146 | " rdf:object ex:Murderer ; \n",
147 | " a rdf:Statement ; \n",
148 | "] .**\n",
149 | "\n",
150 | "**Note: The rdf:type abbreviation \"a\" can only be used at predicate position. At other positions use rdf:type.**\n",
151 | "\n",
152 | "### 1a) Gossip [2 points]\n",
153 | "\n",
154 | "A group of friends gossiped. Bob said something interesting: He said that Eve heard that Mallory cheated on Oscar.\n",
155 | "\n",
156 | "Use nested reification to create a graph of Bob's statement.\n",
157 | "\n",
158 | "Use the following URIs: \n",
159 | "Bob: **http://example.org/#Bob** \n",
160 | "Eve: **http://example.org/#Eve** \n",
161 | "Mallory: **http://example.org/#Mallory** \n",
162 | "Oscar: **http://example.org/#Oscar** \n",
163 | "said: **http://example.org/#said** \n",
164 | "heard: **http://example.org/#heard** \n",
165 | "cheated on: **http://example.org/#cheatedOn** \n",
166 | "\n",
167 | "You may also use all terms from the RDF vocabulary."
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {
174 | "deletable": false,
175 | "nbgrader": {
176 | "cell_type": "code",
177 | "checksum": "65ceb7f2827385c5ab1c896d3275d025",
178 | "grade": false,
179 | "grade_id": "cell-242a1b3bec7afe75",
180 | "locked": false,
181 | "schema_version": 3,
182 | "solution": true,
183 | "task": false
184 | }
185 | },
186 | "outputs": [],
187 | "source": [
188 | "%%rdf turtle -l gossip\n",
189 | "### YOUR SOLUTION HERE"
190 | ]
191 | },
192 | {
193 | "cell_type": "code",
194 | "execution_count": null,
195 | "metadata": {
196 | "deletable": false,
197 | "editable": false,
198 | "nbgrader": {
199 | "cell_type": "code",
200 | "checksum": "de87358429fc1563391a37a122e039ab",
201 | "grade": true,
202 | "grade_id": "cell-c5d0a196cb766a04",
203 | "locked": true,
204 | "points": 0.5,
205 | "schema_version": 3,
206 | "solution": false,
207 | "task": false
208 | }
209 | },
210 | "outputs": [],
211 | "source": [
212 | "# This test will check whether your graph contains a statement by Bob. [0.5 points]\n",
213 | "store = %rdf -r\n",
214 | "g = store['rdfgraphs']['gossip']\n",
215 | "res = None\n",
216 | "res = list(g.objects(subject=uri(ex, \"Bob\"), predicate=uri(ex, \"said\")))\n",
217 | "x = triple.format(ex+\"Bob\", ex+\"said\", \"Blank node\")\n",
218 | "assert len(res) > 0, notContain.format(x)\n",
219 | "assert len(res) <= 1, eMultiple.format(x)\n",
220 | "assert isinstance(res[0], BNode), eBNode.format(x,res[0].n3())"
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "execution_count": null,
226 | "metadata": {
227 | "deletable": false,
228 | "editable": false,
229 | "nbgrader": {
230 | "cell_type": "code",
231 | "checksum": "3c9fb2cbf9cd35f1bf3349ab28c2f86c",
232 | "grade": true,
233 | "grade_id": "cell-73c5f331e3d920dc",
234 | "locked": true,
235 | "points": 0.5,
236 | "schema_version": 3,
237 | "solution": false,
238 | "task": false
239 | }
240 | },
241 | "outputs": [],
242 | "source": [
243 | "# This test will check whether a statement in your graph is about what Eve heard. [0.5 points]\n",
244 | "store = %rdf -r\n",
245 | "g = store['rdfgraphs']['gossip']\n",
246 | "(res,res2) = (None, None)\n",
247 | "res = list(g.subjects(object=uri(ex, \"Eve\"), predicate=RDF.subject))\n",
248 | "x = triple.format(\"Blank node\", RDF.subject, ex+\"Eve\")\n",
249 | "assert len(res) > 0, notContain.format(x)\n",
250 | "assert len(res) <= 1, eMultiple.format(x)\n",
251 | "assert isinstance(res[0], BNode), eBNode.format(x,res[0].n3())"
252 | ]
253 | },
254 | {
255 | "cell_type": "code",
256 | "execution_count": null,
257 | "metadata": {
258 | "deletable": false,
259 | "editable": false,
260 | "nbgrader": {
261 | "cell_type": "code",
262 | "checksum": "28c72e800624f06681356ac12569df53",
263 | "grade": true,
264 | "grade_id": "cell-dae42e7390f903cf",
265 | "locked": true,
266 | "points": 1,
267 | "schema_version": 3,
268 | "solution": false,
269 | "task": false
270 | }
271 | },
272 | "outputs": [],
273 | "source": [
274 | "# This test will check whether the statement of what Eve heard is correct. [1 point]"
275 | ]
276 | },
277 | {
278 | "cell_type": "markdown",
279 | "metadata": {
280 | "deletable": false,
281 | "editable": false,
282 | "nbgrader": {
283 | "cell_type": "markdown",
284 | "checksum": "835fd5d9c54b1b3e2e7e498dd2164e09",
285 | "grade": false,
286 | "grade_id": "cell-9ebba7ead61e0295",
287 | "locked": true,
288 | "schema_version": 3,
289 | "solution": false,
290 | "task": false
291 | }
292 | },
293 | "source": [
294 | "### Primary values\n",
295 | "\n",
296 | "When using n-ary relations, it sometimes makes sense to have a **primary value**. The address example from the second exercise sheet was an n-ary relation but none of its values (street, house number, zip code, city) could be considered primary. But when talking about the price of somethinge in a specific currency, the price could be considered primary while the currency is a complementing value. To declare a primary value in an n-ary relation, one uses the **rdf:value** property defined in the RDF vocabulary. For example if a cheeseburger costs 1 Euro, you would write:\n",
297 | "\n",
298 | "**ex:Cheeseburger ex:price \\[ \n",
299 | " rdf:value \"1\" ; \n",
300 | " ex:currency ex:Euro ; \n",
301 | "\\] .**\n",
302 | "\n",
303 | "### 1b) Experiment [2 points]\n",
304 | "\n",
305 | "Some physicists conduct an experiment to determine the gravitational acceleration. The result of the experiment is **9.81 m/s^2** with an **uncertainty of 0.02**. Because the gravitational acceleration varies based on location, we also need to know the location which is **latitude 50.78167189752423** and **longitude 6.049597427163315**. Use an n-ary relation with primary value to model this information.\n",
306 | "\n",
307 | "Use the following URIs: \n",
308 | "Experiment: **http://example.org/#Experiment** \n",
309 | "result: **http://example.org/#result** \n",
310 | "unit: **http://example.org/#unit** \n",
311 | "uncertainty: **http://example.org/#uncertainty** \n",
312 | "latitude: **http://example.org/#latitude** \n",
313 | "longitude: **http://example.org/#longitude** \n",
314 | "\n",
315 | "Use xsd:decimal as datatype for decimal values and omit the datatype for string values. You may also use all terms from the RDF vocabulary."
316 | ]
317 | },
318 | {
319 | "cell_type": "code",
320 | "execution_count": null,
321 | "metadata": {
322 | "deletable": false,
323 | "nbgrader": {
324 | "cell_type": "code",
325 | "checksum": "824238b79ebd6a5286f126634db06111",
326 | "grade": false,
327 | "grade_id": "cell-e8ac7b236e8be8ce",
328 | "locked": false,
329 | "schema_version": 3,
330 | "solution": true,
331 | "task": false
332 | }
333 | },
334 | "outputs": [],
335 | "source": [
336 | "%%rdf turtle -l experiment\n",
337 | "### YOUR SOLUTION HERE"
338 | ]
339 | },
340 | {
341 | "cell_type": "code",
342 | "execution_count": null,
343 | "metadata": {
344 | "deletable": false,
345 | "editable": false,
346 | "nbgrader": {
347 | "cell_type": "code",
348 | "checksum": "02cc241ff9727eb088be2db6763d5a1f",
349 | "grade": true,
350 | "grade_id": "cell-f98d7467ba33b658",
351 | "locked": true,
352 | "points": 1,
353 | "schema_version": 3,
354 | "solution": false,
355 | "task": false
356 | }
357 | },
358 | "outputs": [],
359 | "source": [
360 | "# This test will check whether your graph contains the result of the experiment\n",
361 | "# and whether the primary value was chosen correctly. [1 point]\n",
362 | "store = %rdf -r\n",
363 | "g = store['rdfgraphs']['experiment']\n",
364 | "res = None\n",
365 | "res = list(g.objects(subject=uri(ex, \"Experiment\"), predicate=uri(ex, \"result\")))\n",
366 | "x = triple.format(ex+\"Experiment\", ex+\"result\", \"Blank node\")\n",
367 | "assert len(res) > 0, notContain.format(x)\n",
368 | "assert len(res) <= 1, eMultiple.format(x)\n",
369 | "assert isinstance(res[0], BNode), eBNode.format(x,res[0].n3())"
370 | ]
371 | },
372 | {
373 | "cell_type": "code",
374 | "execution_count": null,
375 | "metadata": {
376 | "deletable": false,
377 | "editable": false,
378 | "nbgrader": {
379 | "cell_type": "code",
380 | "checksum": "a461a3b71837ef6062524629800a9da0",
381 | "grade": true,
382 | "grade_id": "cell-d67b6ec756729f53",
383 | "locked": true,
384 | "points": 1,
385 | "schema_version": 3,
386 | "solution": false,
387 | "task": false
388 | }
389 | },
390 | "outputs": [],
391 | "source": [
392 | "# This test will check whether your graph contains all complementing values. [1 point]\n",
393 | "# Only gives points if the last test does not fail."
394 | ]
395 | },
396 | {
397 | "cell_type": "markdown",
398 | "metadata": {
399 | "deletable": false,
400 | "editable": false,
401 | "nbgrader": {
402 | "cell_type": "markdown",
403 | "checksum": "6cbde5bcc22a063f85a36a2230fc610f",
404 | "grade": false,
405 | "grade_id": "cell-62b9e77782c2aaa9",
406 | "locked": true,
407 | "schema_version": 3,
408 | "solution": false,
409 | "task": false
410 | }
411 | },
412 | "source": [
413 | "## Task 2: RDF Schema [8 points]\n",
414 | "\n",
415 | "RDF Schema (RDFS) is another [W3C recommended](https://www.w3.org/TR/rdf-schema/) vocabulary. RDFS provides means to specify characteristics of classes and properties independent of their domain. It can be seen as a weak ontology language for defining vocabularies. RDFS splits resources into three types: individuals, classes and properties. Individuals are instances of things, like a specific person or object. Classes are sets of individuals with similar properties like all persons or all cars. Properties describe individuals.\n",
416 | "\n",
417 | "### Classes\n",
418 | "\n",
419 | "Classes are sets of individuals with similar properties. To define our own class, we just have to declare the type of the class resource as **rdfs:Class**:\n",
420 | "\n",
421 | "**ex:Car a rdfs:Class .**\n",
422 | "\n",
423 | "To declare that an individual is part of a class, we also use rdf:type:\n",
424 | "\n",
425 | "**ex:BMW a ex:Car .**\n",
426 | "\n",
427 | "So rdfs:Class is the class containing all classes.\n",
428 | "\n",
429 | "### Properties\n",
430 | "\n",
431 | "As with classes, we can define our own properties to describe resources. For this, we use the class rdf:Property (Note that it is **rdf:Property** NOT rdfs:Property as it is defined in the RDF vocabulary). To define our own property, we just have to declare the type of the resource as **rdf:Property**:\n",
432 | "\n",
433 | "**ex:drives a rdf:Property .**\n",
434 | "\n",
435 | "Then we can use the property:\n",
436 | "\n",
437 | "**ex:Max ex:drives ex:BMW .**\n",
438 | "\n",
439 | "As rdf:Property is the class of all properties, it is also an rdfs:Class.\n",
440 | "\n",
441 | "### Subclasses and Subproperties\n",
442 | "\n",
443 | "While classes and properties are a nice way to organize resources, by themselves they do not provide means of infering new information. For this RDFS defines the two properties **rdfs:subClassOf** and **rdfs:subPropertyOf**. Any individual of a subclass also belongs to the superclass and any triple with the subproperty also holds for the superproperty. For example from the following graph:\n",
444 | "\n",
445 | "**\\# Defining classes and properties \n",
446 | "ex:Car a rdfs:Class . \n",
447 | "ex:Vehicle a rdfs:Class . \n",
448 | "ex:drives a rdf:Property . \n",
449 | "ex:operates a rdf:Property . \n",
450 | "\\# Defining subclass- and subproperty-relations \n",
451 | "ex:Car rdfs:subClassOf ex:Vehicle . \n",
452 | "ex:drives rdfs:subPropertyOf ex:operates . \n",
453 | "\\# Facts \n",
454 | "ex:BMW a ex:Car . \n",
455 | "ex:Max ex:drives ex:BMW .**\n",
456 | "\n",
457 | "these triples can be inferred:\n",
458 | "\n",
459 | "**ex:BMW a ex:Vehicle . \n",
460 | "ex:Max ex:operates ex:BMW .**\n",
461 | "\n",
462 | "Both rdfs:subClassOf and rdfs:subPropertyOf are reflexive and transitive. So all \\[classes/properties\\] are \\[subclasses/subproperties\\] of themselves and when x is a \\[subclass/subproperty\\] of y and y is a \\[subclass/subproperty\\] of z then x is also a \\[subclass/subproperty\\] of z.\n",
463 | "\n",
464 | "To define that two classes or properties are equal, you just add a subclass/subproperty relation in both directions:\n",
465 | "\n",
466 | "**ex:Car rdfs:subClassOf ex:Automobile . \n",
467 | "ex:Automobile rdfs:subClassOf ex:Car . \n",
468 | "ex:drives rdfs:subPropertyOf ex:Steers . \n",
469 | "ex:Steers rdfs:subPropertyOf ex:drives .**\n",
470 | "\n",
471 | "RDFS defines a class rdfs:Resource, which is the superclass of all classes.\n",
472 | "\n",
473 | "### Domains and Ranges\n",
474 | "\n",
475 | "Another way to infer new information is by using property domains and ranges. The domain of a property defines the class of the subject in a triple and the range the class of the object. For this we use the properties **rdfs:domain** and **rdfs:range**. For example, given the graph:\n",
476 | "\n",
477 | "**ex:Car a rdfs:Class . \n",
478 | "ex:Person a rdfs:Class . \n",
479 | "ex:drives a rdf:Property . \n",
480 | "ex:drives rdfs:domain ex:Person . \n",
481 | "ex:drives rdfs:range ex:Car . \n",
482 | "ex:Max ex:drives ex:BMW .**\n",
483 | "\n",
484 | "we can infer the triples:\n",
485 | "\n",
486 | "**ex:Max a ex:Person . \n",
487 | "ex:BMW a ex:Car .**\n",
488 | "\n",
489 | "Because ex:drives has the domain ex:Person and range ex:Car, ex:Max, who appears as subject of ex:drives, has to be a ex:Person, and ex:BMW, which appears as object of ex:drives, has to be a ex:Car.\n",
490 | "\n",
491 | "Many RDFS properties have predefined domains and ranges. For example rdfs:domain and rdfs:range themselves have rdf:Property as a domain and rdfs:Class as range. This means that we can omit the first three triples in the example above as they can be inferred by the fourth and fifth triple.\n",
492 | "\n",
493 | "Be careful when using multiple domains and ranges as they apply conjunctively and not disjunctively. For example:\n",
494 | "\n",
495 | "**ex:drives rdfs:range ex:Car . \n",
496 | "ex:drives rdfs:range ex:Ship .**\n",
497 | "\n",
498 | "One would think that this means that the object of ex:drives is either a car or a ship but it means that its object is a car and a ship at the same time which is probably unintended. A better way to model this would be the following:\n",
499 | "\n",
500 | "**ex:Car rdfs:subClassOf ex:Vehicle . \n",
501 | "ex:Ship rdfs:subClassOf ex:Vehicle . \n",
502 | "ex:drives rdfs:range ex:Vehicle .**\n",
503 | "\n",
504 | "### Comparison to Object-Oriented Programming\n",
505 | "\n",
506 | "One may compare the class and property system of RDFS to object-oriented programming but this can be misleading. In oop, one defines classes in terms of what properties they have, while in RDFS one defines properties in terms of which classes of instances they apply to. So instead of saying: \"x belongs to class y so it has to have property z\", we say \"Property z is used with x, so x has to belong to class y\".\n",
507 | "\n",
508 | "\n",
509 | "### Other Useful Properties\n",
510 | "\n",
511 | "RDFS also defines the following useful properties:\n",
512 | "\n",
513 | "**rdfs:label**: Specifies a human-readable label for a resource. We already used this in prior exercises to give resources literal names.\n",
514 | "\n",
515 | "**rdfs:comment**: Specifies a human-readable description for a resource.\n",
516 | "\n",
517 | "**rdfs:seeAlso**: Specifies a generic link. Useful for linking resources to similar resources or resources that provide additional information.\n",
518 | "\n",
519 | "**rdfs:isDefinedBy**: Relate a resource to its definition. Can be used to indicate a vocabulary in which the resource is defined.\n",
520 | "\n",
521 | "### Entailment\n",
522 | "\n",
523 | "Using the RDFS vocabulary and its rules, we can now rdfs-entail a graph. If a graph A rdfs-entails a graph B, every rdfs-interpretation which satisfies graph A also satisfies graph B. With this we can implicitly deduct semantics for our graphs instead of explicitly specifying the meaning of information. For example, we can describe 'what a car is' without using attributes describing it. We implicitly specify it by stating that a car is a vehicle and that vehicles can be driven. Using this, we can give a machine interpretable meaning to resources and provide a more general description. RDFS-Entailment is only one of many possible entailment regimes. For more information on RDFS-Entailment, other entailment regimes and rdf semantics in general please consult this [W3C recommendation](https://www.w3.org/TR/rdf11-mt/).\n",
524 | "\n",
525 | "### 2a) Pets [4 points]\n",
526 | "\n",
527 | "Model the following information using the RDFS vocabulary: \n",
528 | "All mammals are animals. All Humans, Canines and Felines are mammals. All dogs and foxes are Canines. Only humans have pets (http://example.org/#hasPet). Having a dog (http://example.org/#hasDog) means having a pet which is a dog.\n",
529 | "\n",
530 | "Also add that Max has a Dog with the name (rdfs:label) \"Spike\" and the description (rdfs:comment) \"A gray bulldog. He likes to chase cats.\".\n",
531 | "\n",
532 | "Use the following URIs: \n",
533 | "Animals: **http://example.org/#Animal** \n",
534 | "Mammals: **http://example.org/#Mammal** \n",
535 | "Humans: **http://example.org/#Human** \n",
536 | "Canines: **http://example.org/#Canine** \n",
537 | "Felines: **http://example.org/#Feline** \n",
538 | "Dogs: **http://example.org/#Dog** \n",
539 | "Foxes: **http://example.org/#Fox** \n",
540 | "Has a pet: **http://example.org/#hasPet** \n",
541 | "Has a dog: **http://example.org/#hasDog** \n",
542 | "Max: **http://example.org/#Max** \n",
543 | "Spike: **http://example.org/#Spike**\n",
544 | "\n",
545 | "You may also use all terms from the RDF and RDFS vocabularies. You may omit or keep as many triples as long as the rdfs-entailment closure stays the same."
546 | ]
547 | },
548 | {
549 | "cell_type": "code",
550 | "execution_count": null,
551 | "metadata": {
552 | "deletable": false,
553 | "nbgrader": {
554 | "cell_type": "code",
555 | "checksum": "fd562bb87d0358fc138c113e18ad0c5b",
556 | "grade": false,
557 | "grade_id": "cell-29a88032a0541ea5",
558 | "locked": false,
559 | "schema_version": 3,
560 | "solution": true,
561 | "task": false
562 | }
563 | },
564 | "outputs": [],
565 | "source": [
566 | "%%rdf turtle -l pets\n",
567 | "# These are just some axiomatic triples. Do not remove them.\n",
568 | "rdfs:subClassOf rdfs:domain rdfs:Class .\n",
569 | "rdfs:subClassOf rdfs:range rdfs:Class .\n",
570 | "rdfs:range rdfs:range rdfs:Class .\n",
571 | "rdfs:range rdfs:domain rdf:Property .\n",
572 | "rdfs:domain rdfs:range rdfs:Class .\n",
573 | "rdfs:domain rdfs:domain rdf:Property .\n",
574 | "\n",
575 | "### YOUR SOLUTION HERE"
576 | ]
577 | },
578 | {
579 | "cell_type": "markdown",
580 | "metadata": {
581 | "deletable": false,
582 | "editable": false,
583 | "nbgrader": {
584 | "cell_type": "markdown",
585 | "checksum": "6e2624d1f00a5fae8cf82f825ee61616",
586 | "grade": false,
587 | "grade_id": "cell-5aed95188f6f9a1d",
588 | "locked": true,
589 | "schema_version": 3,
590 | "solution": false,
591 | "task": false
592 | }
593 | },
594 | "source": [
595 | "The cell below will automatically compute the closure of the rdfs-entailment for your graph. The extension uses a brute-force approach and only a finite set of axiomatic triples. It also omits most axiomatic triples to make the graph less cluttered so the closure will not be complete but best-effort. Note that this graph grows quite quickly."
596 | ]
597 | },
598 | {
599 | "cell_type": "code",
600 | "execution_count": null,
601 | "metadata": {
602 | "deletable": false,
603 | "editable": false,
604 | "nbgrader": {
605 | "cell_type": "code",
606 | "checksum": "4cab0e2209ac2db99010c9005ed4e53b",
607 | "grade": false,
608 | "grade_id": "cell-172648f531b503d8",
609 | "locked": true,
610 | "schema_version": 3,
611 | "solution": false,
612 | "task": false
613 | }
614 | },
615 | "outputs": [],
616 | "source": [
617 | "# This cell will compute the closure of the rdfs-entailment of your graph and draw it.\n",
618 | "%rdf graph entail-rdfs -l pets\n",
619 | "%rdf graph draw -l pets"
620 | ]
621 | },
622 | {
623 | "cell_type": "code",
624 | "execution_count": null,
625 | "metadata": {
626 | "deletable": false,
627 | "editable": false,
628 | "nbgrader": {
629 | "cell_type": "code",
630 | "checksum": "a94b904955eb7de9a24d261b00e27ef8",
631 | "grade": true,
632 | "grade_id": "cell-545a303d2dc929f7",
633 | "locked": true,
634 | "points": 1,
635 | "schema_version": 3,
636 | "solution": false,
637 | "task": false
638 | }
639 | },
640 | "outputs": [],
641 | "source": [
642 | "# This test will check whether the entailment closure of your graph contains\n",
643 | "# all necessary class and property definitions. [1 point]\n",
644 | "%rdf graph entail-rdfs -l pets\n",
645 | "store = %rdf -r\n",
646 | "g = store['rdfgraphs']['pets']\n",
647 | "containCheck(g, uri(ex, \"Animal\"), RDF.type, RDFS.Class)\n",
648 | "containCheck(g, uri(ex, \"Mammal\"), RDF.type, RDFS.Class)\n",
649 | "containCheck(g, uri(ex, \"hasPet\"), RDF.type, RDF.Property)"
650 | ]
651 | },
652 | {
653 | "cell_type": "code",
654 | "execution_count": null,
655 | "metadata": {
656 | "deletable": false,
657 | "editable": false,
658 | "nbgrader": {
659 | "cell_type": "code",
660 | "checksum": "869f7d9355cc428b6881c2b032364b6c",
661 | "grade": true,
662 | "grade_id": "cell-870e8045b6da1343",
663 | "locked": true,
664 | "points": 1,
665 | "schema_version": 3,
666 | "solution": false,
667 | "task": false
668 | }
669 | },
670 | "outputs": [],
671 | "source": [
672 | "# This test will check whether the entailment closure of your graph contains\n",
673 | "# all necessary subclass and subproperty definitions. [1 point]\n",
674 | "%rdf graph entail-rdfs -l pets\n",
675 | "store = %rdf -r\n",
676 | "g = store['rdfgraphs']['pets']\n",
677 | "containCheck(g, uri(ex, \"Mammal\"), RDFS.subClassOf, uri(ex, \"Animal\"))\n",
678 | "containCheck(g, uri(ex, \"Human\"), RDFS.subClassOf, uri(ex, \"Animal\"))"
679 | ]
680 | },
681 | {
682 | "cell_type": "code",
683 | "execution_count": null,
684 | "metadata": {
685 | "deletable": false,
686 | "editable": false,
687 | "nbgrader": {
688 | "cell_type": "code",
689 | "checksum": "f178619f8c8eb742c6f3ded04b251edd",
690 | "grade": true,
691 | "grade_id": "cell-bb9fd35fae47263f",
692 | "locked": true,
693 | "points": 1,
694 | "schema_version": 3,
695 | "solution": false,
696 | "task": false
697 | }
698 | },
699 | "outputs": [],
700 | "source": [
701 | "# This test will check whether the entailment closure of your graph contains\n",
702 | "# all necessary range and domain definitions. [1 point]\n",
703 | "%rdf graph entail-rdfs -l pets\n",
704 | "store = %rdf -r\n",
705 | "g = store['rdfgraphs']['pets']\n",
706 | "containCheck(g, uri(ex, \"hasPet\"), RDFS.domain, uri(ex, \"Human\"))"
707 | ]
708 | },
709 | {
710 | "cell_type": "code",
711 | "execution_count": null,
712 | "metadata": {
713 | "deletable": false,
714 | "editable": false,
715 | "nbgrader": {
716 | "cell_type": "code",
717 | "checksum": "6d8bad43c1f28c95b6f387a0aa5666bb",
718 | "grade": true,
719 | "grade_id": "cell-98cbe50027bad490",
720 | "locked": true,
721 | "points": 1,
722 | "schema_version": 3,
723 | "solution": false,
724 | "task": false
725 | }
726 | },
727 | "outputs": [],
728 | "source": [
729 | "# This test will check whether the entailment closure of your graph contains\n",
730 | "# all specified facts. [1 point]"
731 | ]
732 | },
733 | {
734 | "cell_type": "markdown",
735 | "metadata": {
736 | "deletable": false,
737 | "editable": false,
738 | "nbgrader": {
739 | "cell_type": "markdown",
740 | "checksum": "f042cdc8a3a53b883d268f41030e49e6",
741 | "grade": false,
742 | "grade_id": "cell-0bfc8cc310a8f149",
743 | "locked": true,
744 | "schema_version": 3,
745 | "solution": false,
746 | "task": false
747 | }
748 | },
749 | "source": [
750 | "#### 2b) Library [4 points]\n",
751 | "\n",
752 | "Model the following information using the RDFS vocabulary: All books and movies are mediums. The creator of a medium is a person and only mediums have a creator. Only books have an author and the author of a book is also the creator. Only mediums have titles and a publish date.\n",
753 | "\n",
754 | "Also add that Douglas Adams is the author of a book with the title \"The Hitchhiker's Guide to the Galaxy\" and published \"1979-10-12\".\n",
755 | "\n",
756 | "Use the following URIs: \n",
757 | "Medium: **http://example.org/#Medium** \n",
758 | "Books: **http://example.org/#Book** \n",
759 | "Movies: **http://example.org/#Movie** \n",
760 | "Persons: **http://example.org/#Person** \n",
761 | "creator: **http://example.org/#createdBy** \n",
762 | "author: **http://example.org/#authoredBy** \n",
763 | "title: **http://example.org/#title** \n",
764 | "publish date: **http://example.org/#published** \n",
765 | "Douglas Adams: **http://example.org/#DouglasAdams** \n",
766 | "The Hitchhiker's Guide to the Galaxy: **http://example.org/#HitchhikersGuide**\n",
767 | "\n",
768 | "You may use all terms from the RDFS vocabulary. Omit datatypes of literals."
769 | ]
770 | },
771 | {
772 | "cell_type": "code",
773 | "execution_count": null,
774 | "metadata": {
775 | "deletable": false,
776 | "nbgrader": {
777 | "cell_type": "code",
778 | "checksum": "d3a6176b68fed76a0b00e7ef281ecb7a",
779 | "grade": false,
780 | "grade_id": "cell-f3aaa3f152446c75",
781 | "locked": false,
782 | "schema_version": 3,
783 | "solution": true,
784 | "task": false
785 | }
786 | },
787 | "outputs": [],
788 | "source": [
789 | "%%rdf turtle -l library\n",
790 | "# These are just some axiomatic triples. Do not remove them.\n",
791 | "rdfs:subClassOf rdfs:domain rdfs:Class .\n",
792 | "rdfs:subClassOf rdfs:range rdfs:Class .\n",
793 | "rdfs:range rdfs:range rdfs:Class .\n",
794 | "rdfs:range rdfs:domain rdf:Property .\n",
795 | "rdfs:domain rdfs:range rdfs:Class .\n",
796 | "rdfs:domain rdfs:domain rdf:Property .\n",
797 | "\n",
798 | "### YOUR SOLUTION HERE"
799 | ]
800 | },
801 | {
802 | "cell_type": "code",
803 | "execution_count": null,
804 | "metadata": {
805 | "deletable": false,
806 | "editable": false,
807 | "nbgrader": {
808 | "cell_type": "code",
809 | "checksum": "2d1bb46414ec72a592ec4ec1e31e1eeb",
810 | "grade": false,
811 | "grade_id": "cell-1bf611f650e94a71",
812 | "locked": true,
813 | "schema_version": 3,
814 | "solution": false,
815 | "task": false
816 | }
817 | },
818 | "outputs": [],
819 | "source": [
820 | "# This cell will compute the closure of the rdfs-entailment of your graph and draw it.\n",
821 | "%rdf graph entail-rdfs -l library\n",
822 | "%rdf graph draw -l library"
823 | ]
824 | },
825 | {
826 | "cell_type": "code",
827 | "execution_count": null,
828 | "metadata": {
829 | "deletable": false,
830 | "editable": false,
831 | "nbgrader": {
832 | "cell_type": "code",
833 | "checksum": "5ed490f52a613fecc4af92d779e2ec6a",
834 | "grade": true,
835 | "grade_id": "cell-37dd9e59365f85a7",
836 | "locked": true,
837 | "points": 1,
838 | "schema_version": 3,
839 | "solution": false,
840 | "task": false
841 | }
842 | },
843 | "outputs": [],
844 | "source": [
845 | "# This test will check whether the entailment closure of your graph contains\n",
846 | "# all necessary class and property definitions. [1 point]"
847 | ]
848 | },
849 | {
850 | "cell_type": "code",
851 | "execution_count": null,
852 | "metadata": {
853 | "deletable": false,
854 | "editable": false,
855 | "nbgrader": {
856 | "cell_type": "code",
857 | "checksum": "9d6945a330859f0fcdd7a5f35e785d17",
858 | "grade": true,
859 | "grade_id": "cell-324f82b1b688bdd8",
860 | "locked": true,
861 | "points": 1,
862 | "schema_version": 3,
863 | "solution": false,
864 | "task": false
865 | }
866 | },
867 | "outputs": [],
868 | "source": [
869 | "# This test will check whether the entailment closure of your graph contains\n",
870 | "# all necessary subclass and subproperty definitions. [1 point]"
871 | ]
872 | },
873 | {
874 | "cell_type": "code",
875 | "execution_count": null,
876 | "metadata": {
877 | "deletable": false,
878 | "editable": false,
879 | "nbgrader": {
880 | "cell_type": "code",
881 | "checksum": "da72dc2a4daaa4f27f6d061981c09796",
882 | "grade": true,
883 | "grade_id": "cell-3a66804cfcbe5d62",
884 | "locked": true,
885 | "points": 1,
886 | "schema_version": 3,
887 | "solution": false,
888 | "task": false
889 | }
890 | },
891 | "outputs": [],
892 | "source": [
893 | "# This test will check whether the entailment closure of your graph contains\n",
894 | "# all necessary range and domain definitions. [1 point]"
895 | ]
896 | },
897 | {
898 | "cell_type": "code",
899 | "execution_count": null,
900 | "metadata": {
901 | "deletable": false,
902 | "editable": false,
903 | "nbgrader": {
904 | "cell_type": "code",
905 | "checksum": "dba4e3c7dc8db02e4e86ae50d2fc66c3",
906 | "grade": true,
907 | "grade_id": "cell-1deb9b6a3345d701",
908 | "locked": true,
909 | "points": 1,
910 | "schema_version": 3,
911 | "solution": false,
912 | "task": false
913 | }
914 | },
915 | "outputs": [],
916 | "source": [
917 | "# This test will check whether the entailment closure of your graph contains\n",
918 | "# all specified facts. [1 point]"
919 | ]
920 | },
921 | {
922 | "cell_type": "markdown",
923 | "metadata": {
924 | "deletable": false,
925 | "editable": false,
926 | "nbgrader": {
927 | "cell_type": "markdown",
928 | "checksum": "3e97ad7a0d07adae2cd320a3dc8bc1bc",
929 | "grade": false,
930 | "grade_id": "cell-a5cd7e400e7f49d8",
931 | "locked": true,
932 | "schema_version": 3,
933 | "solution": false,
934 | "task": false
935 | }
936 | },
937 | "source": [
938 | "## Other Vocabularies/Ontologies\n",
939 | "\n",
940 | "We looked at the RDF and RDFS vocabularies which are both very basic, domain-independent vocabularies. There are countless more domain specific vocabularies which provide classes, properties or even individuals with agreed upon meaning. We can use these vocabularies to make our graphs easier to interpret by humans and machines. For example, above we defined the properties creator and publish date. These properties are very general and thus often used. If everyone defined their own properties, we would have many properties with the same meaning. Instead if everyone agreed to use a specific URI for specifying e.g. the creator of a resource, it would be a lot easier to work on multiple graphs with different origin. An example for such a vocabulary is the well known Dublin Core(TM) vocabulary. This vocabulary defines 15 core properties to describe resources like creator, date, title, description, format and similar. "
941 | ]
942 | }
943 | ],
944 | "metadata": {
945 | "kernelspec": {
946 | "display_name": "Python 3",
947 | "language": "python",
948 | "name": "python3"
949 | },
950 | "language_info": {
951 | "codemirror_mode": {
952 | "name": "ipython",
953 | "version": 3
954 | },
955 | "file_extension": ".py",
956 | "mimetype": "text/x-python",
957 | "name": "python",
958 | "nbconvert_exporter": "python",
959 | "pygments_lexer": "ipython3",
960 | "version": "3.8.5"
961 | }
962 | },
963 | "nbformat": 4,
964 | "nbformat_minor": 4
965 | }
966 |
--------------------------------------------------------------------------------
/Notebooks/SemWebEx5.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "deletable": false,
8 | "editable": false,
9 | "nbgrader": {
10 | "cell_type": "code",
11 | "checksum": "aa1071c068c1cb9b0fdcb56a29fdafe4",
12 | "grade": false,
13 | "grade_id": "cell-13e4041a44715c7e",
14 | "locked": true,
15 | "schema_version": 3,
16 | "solution": false,
17 | "task": false
18 | }
19 | },
20 | "outputs": [],
21 | "source": [
22 | "%reload_ext jupyter-rdfify"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": null,
28 | "metadata": {
29 | "deletable": false,
30 | "editable": false,
31 | "nbgrader": {
32 | "cell_type": "code",
33 | "checksum": "80aa568449d34cf1ada8ffa83b77d4d7",
34 | "grade": true,
35 | "grade_id": "cell-d2f59fff5596a80a",
36 | "locked": true,
37 | "points": 0,
38 | "schema_version": 3,
39 | "solution": false,
40 | "task": false
41 | }
42 | },
43 | "outputs": [],
44 | "source": [
45 | "# This is a placeholder cell for test initialization. Ignore it."
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {
51 | "deletable": false,
52 | "editable": false,
53 | "nbgrader": {
54 | "cell_type": "markdown",
55 | "checksum": "51d81a585821ece01a409aa02ac396f6",
56 | "grade": false,
57 | "grade_id": "cell-c6e1bc3176fa42bc",
58 | "locked": true,
59 | "schema_version": 3,
60 | "solution": false,
61 | "task": false
62 | }
63 | },
64 | "source": [
65 | "The two cells below will define some prefixes for you. You can use them throughout the sheet."
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {
72 | "deletable": false,
73 | "editable": false,
74 | "nbgrader": {
75 | "cell_type": "code",
76 | "checksum": "2137bf307f0eca9fe5fd7755bd2311e2",
77 | "grade": false,
78 | "grade_id": "cell-62474234fa7cf591",
79 | "locked": true,
80 | "schema_version": 3,
81 | "solution": false,
82 | "task": false
83 | }
84 | },
85 | "outputs": [],
86 | "source": [
87 | "%%rdf shex prefix\n",
88 | "PREFIX rdf: \n",
89 | "PREFIX xsd: "
90 | ]
91 | },
92 | {
93 | "cell_type": "code",
94 | "execution_count": null,
95 | "metadata": {
96 | "deletable": false,
97 | "editable": false,
98 | "nbgrader": {
99 | "cell_type": "code",
100 | "checksum": "0f2e92c6ea306ad6f63f51f1bf3b7783",
101 | "grade": false,
102 | "grade_id": "cell-aac14ff6a9b06ac7",
103 | "locked": true,
104 | "schema_version": 3,
105 | "solution": false,
106 | "task": false
107 | }
108 | },
109 | "outputs": [],
110 | "source": [
111 | "%%rdf turtle --prefix\n",
112 | "PREFIX rdf: \n",
113 | "PREFIX xsd: "
114 | ]
115 | },
116 | {
117 | "cell_type": "markdown",
118 | "metadata": {
119 | "deletable": false,
120 | "editable": false,
121 | "nbgrader": {
122 | "cell_type": "markdown",
123 | "checksum": "9c4237870117cf93f2266ed25cd20053",
124 | "grade": false,
125 | "grade_id": "cell-4f109d08e6827f4d",
126 | "locked": true,
127 | "schema_version": 3,
128 | "solution": false,
129 | "task": false
130 | }
131 | },
132 | "source": [
133 | "# Shape Validation\n",
134 | "\n",
135 | "RDF is a very general data model which can be used to express pretty much anything. But this is both its greatest strength and greatest weakness. It does not have a clear structure and thus maps poorly to common programming language data structures. The vocabularies we have introduced so far may seem like a good start to structuring our RDF data. Even though RDFS is called RDF *Schema* it is used to define vocabularies, not for validating data structures as it isn't expressive enough. OWL is a lot more expressive than RDFS but is targeted at logic modelling, not validity constraining. So these vocabularies do not help us in this matter. Another possible way would be to use SPARQL ASK queries. While ASK queries are ideal to validate constraints as it is very expressive and has efficient implementations, reading, writing and understanding said ASK queries is difficult even for simple constraints.\n",
136 | "\n",
137 | "This is why we need a way to describe and validate our RDF data. **ShEx** (Shape Expression Language) and SHACL (Shape Constraint Language) are both high level, concise languages to define schemata. A schema specifies shape constraints that a node must fulfill to pass the validation. In this lecture we will focus on ShEx.\n",
138 | "\n",
139 | "# ShEx (ShExC)\n",
140 | "\n",
141 | "ShEx**C** is a compact syntax to define ShEx Schemata. It is inspired by Turtle and thus reuses many of its definitions like prefix declaration (using the PREFIX keyword as seen below), the **a** keyword for rdf:type and that keywords are case insensitive (and = AND = AnD). A Schema is a set of shape expressions and a shape expression is a labeled pattern. Shape expression patterns specify constraints for a focus node (the node tested against the pattern) and its neighborhood (the set of incoming and outgoing triples). The following is a schema with a very basic shape expression:\n",
142 | "\n",
143 | "**PREFIX ex: <http://example.org/> \n",
144 | "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>**\n",
145 | "\n",
146 | "**<StudentShape> { \n",
147 | " ex:name xsd:string \n",
148 | "}**\n",
149 | "\n",
150 | "This shape expression has the label StudentShape (labels can be URIs or blank nodes) and contains a pattern which constrains a student to only have one outgoing triple with predicate ex:name which must have the type xsd:string. The following is a graph which passes the validation against the above schema:\n",
151 | "\n",
152 | "**ex:Max ex:name \"Maximiliam Mustermann\" .**\n",
153 | "\n",
154 | "Here are some graphs which would fail the validation:\n",
155 | "\n",
156 | "**ex:Max ex:name \"Maximiliam Mustermann\"@de .** \n",
157 | "Because the datatype is rdf:langString not xsd:string\n",
158 | "\n",
159 | "**ex:Max ex:name \"Maximiliam Mustermann\" , \"Max Mustermann\" .** \n",
160 | "Because **two** ex:name triples are found.\n",
161 | "\n",
162 | "**ex:Max foaf:name \"Maximiliam Mustermann\" .** \n",
163 | "Because no ex:name triple is found (foaf:name was used).\n",
164 | "\n",
165 | "## Grouping\n",
166 | "\n",
167 | "To group multiple component in a pattern, one uses semicolons:\n",
168 | "\n",
169 | "**<StudentShape> { \n",
170 | " ex:name xsd:string ; \n",
171 | " ex:age xsd:integer ; \n",
172 | " ex:email xsd:string \n",
173 | "}**\n",
174 | "\n",
175 | "The following graph passes:\n",
176 | "\n",
177 | "**ex:Max ex:name \"Max\" ; \n",
178 | " ex:age \"5\"^^xsd:integer ; \n",
179 | " ex:email \"max.mustermann@rwth-aachen.de\" .**\n",
180 | "\n",
181 | "## Cardinalities\n",
182 | "\n",
183 | "One can specify a cardinality for each pattern component. The cardinality notation on ShEx is inspired by regular expressions and the default cardinality is {1,1}. The following table explains all possible notations:\n",
184 | "\n",
185 | "| Notation | Meaning |\n",
186 | "| --- | --- |\n",
187 | "| * | 0 or more |\n",
188 | "| + | 1 or more |\n",
189 | "| ? | 0 or 1 |\n",
190 | "| {m} | Exactly m occurences |\n",
191 | "| {m,n} | Between m and n occurences |\n",
192 | "| {m,} | m or more occurences |\n",
193 | "\n",
194 | "To specify that the email of a student is optional, that a student has to have at least one but can have multiple names and that he can have up to two mentors, one would use the following shape expression:\n",
195 | "\n",
196 | "**<StudentShape> { \n",
197 | " ex:name xsd:string + ; \n",
198 | " ex:mentor IRI {0,2} ; \n",
199 | " ex:email xsd:string ? \n",
200 | "}**\n",
201 | "\n",
202 | "## Alternatives\n",
203 | "\n",
204 | "The pipe operator ( | ) is used to declare alternatives. You can use parantheses to group alternatives. For example, to specify that a student can have either a full name or a first and last name but has to have an email address:\n",
205 | "\n",
206 | "**<StudentShape> { \n",
207 | " ( \n",
208 | " ex:fullName xsd:string | \n",
209 | " ex:firstName xsd:string ; \n",
210 | " ex:lastName xsd:string \n",
211 | " ) ; \n",
212 | " ex:email xsd:string \n",
213 | "}**\n",
214 | "\n",
215 | "## Value Expressions\n",
216 | "\n",
217 | "We have already used specific datatypes and have seen the keyword IRI being used in the cardinality example but there are many more value expressions which are listed in the following table:\n",
218 | "\n",
219 | "| Type | Example | Description |\n",
220 | "|:--- |:--- |:--- |\n",
221 | "| Anything | **.** | The object can be anything |\n",
222 | "| Datatype | xsd:string | Matches a value of type xsd:string |\n",
223 | "| Kind | IRI BNode Literal NonLiteral | The object must have that kind |\n",
224 | "| Value set | \\[ex:Male ex:Female ex:Other\\] | The value must be an element of that set |\n",
225 | "| Reference | @<StudentShape> | The object must have the shape <StudentShape> |\n",
226 | "| Composed | xsd:string OR IRI | The composition of value expressions using OR, AND, NOT |\n",
227 | "| IRI Range | \\[foaf:~\\] | Start with the IRI associated with foaf. See Value set. |\n",
228 | "| Exclusion | \\[ex:~ -ex:excluded\\] | Any value except ex:excluded. See Value set. |\n",
229 | "\n",
230 | "An example which uses many of the above expressions:\n",
231 | "\n",
232 | "**<StudentShape> { \n",
233 | " ex:name xsd:string ; \n",
234 | " ex:mentor @<StudentShape> {0,2} ; \n",
235 | " ex:gender [ex:Male ex:Female ex:Other] ; \n",
236 | " ex:university IRI OR BNode ; \n",
237 | " ex:status [status:~ -status:Exmatriculated] ; \n",
238 | " rdfs:seeAlso . \\* \n",
239 | "}**\n",
240 | "\n",
241 | "## Facets on Datatypes\n",
242 | "\n",
243 | "It is possible to qualify the datatype using XML Schema facets. Some possible facets are the following:\n",
244 | "\n",
245 | "| Facet | Description |\n",
246 | "| :--- | :--- |\n",
247 | "| MinInclusive, MaxInclusive, MinExclusive, MaxInclusive | Constraints on numeric values which declare the min/max value allowed (either included or excluded)|\n",
248 | "| TotalDigits, FractionDigits | Constraints on numeric values which declare the total digits and fraction digits allowed |\n",
249 | "| Length, MinLength, MaxLength | Constraints on string values which declare the length allowed, or the min/max length allowed |\n",
250 | "\n",
251 | "An example for facets:\n",
252 | "\n",
253 | "**<StudentShape> { \n",
254 | " ex:name xsd:string MaxLength 10 ; \n",
255 | " ex:matNr xsd:integer MinInclusive 1 MaxInclusive 999999 \n",
256 | "}**"
257 | ]
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "metadata": {
262 | "deletable": false,
263 | "editable": false,
264 | "nbgrader": {
265 | "cell_type": "markdown",
266 | "checksum": "e8ee684295b6203dd3c93d864c9f67d1",
267 | "grade": false,
268 | "grade_id": "cell-3237beb196c62eeb",
269 | "locked": true,
270 | "schema_version": 3,
271 | "solution": false,
272 | "task": false
273 | }
274 | },
275 | "source": [
276 | "## Task 1: Simple Schema [3 points]\n",
277 | "\n",
278 | "Use ShEx to specify the following constraints for a car: \n",
279 | "- A car has a manufacturer which is expressed as an IRI. \n",
280 | "- A car has a vehicle identification number (VIN) which is expressed as a string with 17 characters. \n",
281 | "- A car can have arbitrarily many previous owners which are expressed either as a IRI, a string or a blank node. \n",
282 | "\n",
283 | "The shape expression should be labelled **http://example.org/shapes#CarShape**\n",
284 | "\n",
285 | "Use the following URIs: \n",
286 | "manufacturer: **http://example.org/predicates#manufacturer** \n",
287 | "vehicle identification number: **http://example.org/predicates#vin** \n",
288 | "previous owner: **http://example.org/predicates#previousOwner** \n",
289 | "string: **http://www.w3.org/2001/XMLSchema#string**"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "execution_count": null,
295 | "metadata": {
296 | "deletable": false,
297 | "nbgrader": {
298 | "cell_type": "code",
299 | "checksum": "0e6dcac15459dc7da2e281c231c11291",
300 | "grade": false,
301 | "grade_id": "cell-9af33640b5f6caaa",
302 | "locked": false,
303 | "schema_version": 3,
304 | "solution": true,
305 | "task": false
306 | }
307 | },
308 | "outputs": [],
309 | "source": [
310 | "%%rdf shex parse -l 1\n",
311 | "### YOUR SOLUTION HERE"
312 | ]
313 | },
314 | {
315 | "cell_type": "markdown",
316 | "metadata": {
317 | "deletable": false,
318 | "editable": false,
319 | "nbgrader": {
320 | "cell_type": "markdown",
321 | "checksum": "7b7dc4935e88ff6135c0f47b5a44d5ce",
322 | "grade": false,
323 | "grade_id": "cell-ec0e79a3ae129f64",
324 | "locked": true,
325 | "schema_version": 3,
326 | "solution": false,
327 | "task": false
328 | }
329 | },
330 | "source": [
331 | "The two cells below can be used to check if your solution is correct. Run both of them and check the output of the second cell for errors. The graph below should pass the validation in the second cell. But note that while this is neccessary for your solution to be correct, it is not sufficient!"
332 | ]
333 | },
334 | {
335 | "cell_type": "code",
336 | "execution_count": null,
337 | "metadata": {
338 | "deletable": false,
339 | "editable": false,
340 | "nbgrader": {
341 | "cell_type": "code",
342 | "checksum": "d92efe86be1f7ba411c968fa0015d5e4",
343 | "grade": false,
344 | "grade_id": "cell-a1957290aa0b0dba",
345 | "locked": true,
346 | "schema_version": 3,
347 | "solution": false,
348 | "task": false
349 | }
350 | },
351 | "outputs": [],
352 | "source": [
353 | "%%rdf turtle -l 1check -d none\n",
354 | " ;\n",
355 | " \"WBA12345600000001\" ;\n",
356 | " \"Max Mustermann\", _:1, ."
357 | ]
358 | },
359 | {
360 | "cell_type": "code",
361 | "execution_count": null,
362 | "metadata": {
363 | "deletable": false,
364 | "editable": false,
365 | "nbgrader": {
366 | "cell_type": "code",
367 | "checksum": "5a620f1103c5884c228a156cd795c986",
368 | "grade": false,
369 | "grade_id": "cell-a0b82dd7bf719d47",
370 | "locked": true,
371 | "schema_version": 3,
372 | "solution": false,
373 | "task": false
374 | }
375 | },
376 | "outputs": [],
377 | "source": [
378 | "%rdf shex validate -l 1 -g 1check -s http://example.org/shapes#CarShape"
379 | ]
380 | },
381 | {
382 | "cell_type": "code",
383 | "execution_count": null,
384 | "metadata": {
385 | "deletable": false,
386 | "editable": false,
387 | "nbgrader": {
388 | "cell_type": "code",
389 | "checksum": "023003012d1c1b8a3f59ff4a69347816",
390 | "grade": true,
391 | "grade_id": "cell-6f6d00c77e19e643",
392 | "locked": true,
393 | "points": 1,
394 | "schema_version": 3,
395 | "solution": false,
396 | "task": false
397 | }
398 | },
399 | "outputs": [],
400 | "source": [
401 | "# This test will check whether the manufacturer predicate is constrained correctly. [1 point]"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": null,
407 | "metadata": {
408 | "deletable": false,
409 | "editable": false,
410 | "nbgrader": {
411 | "cell_type": "code",
412 | "checksum": "ed5cf2525bb585d4015ef0dac106edeb",
413 | "grade": true,
414 | "grade_id": "cell-ce9f360b2fc68c1d",
415 | "locked": true,
416 | "points": 1,
417 | "schema_version": 3,
418 | "solution": false,
419 | "task": false
420 | }
421 | },
422 | "outputs": [],
423 | "source": [
424 | "# This test will check whether the vehicle identification number predicate is constrained correctly. [1 point]"
425 | ]
426 | },
427 | {
428 | "cell_type": "code",
429 | "execution_count": null,
430 | "metadata": {
431 | "deletable": false,
432 | "editable": false,
433 | "nbgrader": {
434 | "cell_type": "code",
435 | "checksum": "dd04625411e155bab5906d9c2dbd0afc",
436 | "grade": true,
437 | "grade_id": "cell-857d05adbfdba7d8",
438 | "locked": true,
439 | "points": 1,
440 | "schema_version": 3,
441 | "solution": false,
442 | "task": false
443 | }
444 | },
445 | "outputs": [],
446 | "source": [
447 | "# This test will check whether the previous owner predicate is constrained correctly. [1 point]"
448 | ]
449 | },
450 | {
451 | "cell_type": "markdown",
452 | "metadata": {
453 | "deletable": false,
454 | "editable": false,
455 | "nbgrader": {
456 | "cell_type": "markdown",
457 | "checksum": "4f64fa6413d6d9785bc3c32215f1204a",
458 | "grade": false,
459 | "grade_id": "cell-a464451436e20858",
460 | "locked": true,
461 | "schema_version": 3,
462 | "solution": false,
463 | "task": false
464 | }
465 | },
466 | "source": [
467 | "## Task 2: Referencing [4 points]\n",
468 | "\n",
469 | "Use ShEx to model the following schema: \n",
470 | "- A shop has a name which is expressed as a string. \n",
471 | "- A shop must belong to the class commerce. (Note: Value sets with a single element can be used for 'fixed' triples) \n",
472 | "- A product has a name which is expressed as a string. \n",
473 | "- A product either has an ID which is expressed as an integer (use http://www.w3.org/2001/XMLSchema#integer) from 0 inclusive to 99999999 inclusive or alternatively a product code which is expressed as a string with a length between 11 and 13 characters. \n",
474 | "- A shop can sell arbitrarily many products but has to sell at least one. \n",
475 | "\n",
476 | "The shape expressions should be labelled **http://example.org/shapes#ShopShape** and **http://example.org/shapes#ProductShape**\n",
477 | "\n",
478 | "Use the following URIs: \n",
479 | "has name: **http://example.org/predicates#name** \n",
480 | "has id: **http://example.org/predicates#id** \n",
481 | "has product code: **http://example.org/predicates#code** \n",
482 | "sells product: **http://example.org/predicates#sells** \n",
483 | "Commerce (class): **http://example.org/classes#Commerce** "
484 | ]
485 | },
486 | {
487 | "cell_type": "code",
488 | "execution_count": null,
489 | "metadata": {
490 | "deletable": false,
491 | "nbgrader": {
492 | "cell_type": "code",
493 | "checksum": "a719ecca3949ebf873e6f4f7a7180f2e",
494 | "grade": false,
495 | "grade_id": "cell-d55ff5a129ef04df",
496 | "locked": false,
497 | "schema_version": 3,
498 | "solution": true,
499 | "task": false
500 | }
501 | },
502 | "outputs": [],
503 | "source": [
504 | "%%rdf shex parse -l 2\n",
505 | "### YOUR SOLUTION HERE"
506 | ]
507 | },
508 | {
509 | "cell_type": "markdown",
510 | "metadata": {
511 | "deletable": false,
512 | "editable": false,
513 | "nbgrader": {
514 | "cell_type": "markdown",
515 | "checksum": "5d6ea31d4ddbb6fea90b09b01a3994af",
516 | "grade": false,
517 | "grade_id": "cell-054f183b8c79fc29",
518 | "locked": true,
519 | "schema_version": 3,
520 | "solution": false,
521 | "task": false
522 | }
523 | },
524 | "source": [
525 | "You can again check your answer using the two cells below."
526 | ]
527 | },
528 | {
529 | "cell_type": "code",
530 | "execution_count": null,
531 | "metadata": {
532 | "deletable": false,
533 | "editable": false,
534 | "nbgrader": {
535 | "cell_type": "code",
536 | "checksum": "4d3900539e565031ca686e0eb2e91136",
537 | "grade": false,
538 | "grade_id": "cell-bb39b2da6993598c",
539 | "locked": true,
540 | "schema_version": 3,
541 | "solution": false,
542 | "task": false
543 | }
544 | },
545 | "outputs": [],
546 | "source": [
547 | "%%rdf turtle -l 2check -d none\n",
548 | " \"eBuy\" ;\n",
549 | " a ;\n",
550 | " , .\n",
551 | " \"Good Product\" ;\n",
552 | " \"99999999\"^^xsd:integer .\n",
553 | " \"Better Product\" ;\n",
554 | " \"ABCDEF123456\" ."
555 | ]
556 | },
557 | {
558 | "cell_type": "code",
559 | "execution_count": null,
560 | "metadata": {
561 | "deletable": false,
562 | "editable": false,
563 | "nbgrader": {
564 | "cell_type": "code",
565 | "checksum": "8c6d6e78389d91107e4cfaac8652b996",
566 | "grade": false,
567 | "grade_id": "cell-7db224f33f79f9df",
568 | "locked": true,
569 | "schema_version": 3,
570 | "solution": false,
571 | "task": false
572 | }
573 | },
574 | "outputs": [],
575 | "source": [
576 | "%rdf shex validate -l 2 -g 2check -s http://example.org/shapes#ShopShape -f http://example.org/shops#ebuy"
577 | ]
578 | },
579 | {
580 | "cell_type": "code",
581 | "execution_count": null,
582 | "metadata": {
583 | "deletable": false,
584 | "editable": false,
585 | "nbgrader": {
586 | "cell_type": "code",
587 | "checksum": "a167a9137c460e261508ec655a3fa319",
588 | "grade": true,
589 | "grade_id": "cell-2c2bca492b6c540c",
590 | "locked": true,
591 | "points": 1,
592 | "schema_version": 3,
593 | "solution": false,
594 | "task": false
595 | }
596 | },
597 | "outputs": [],
598 | "source": [
599 | "# This test will check if all basic constraints are correct. [1 point]"
600 | ]
601 | },
602 | {
603 | "cell_type": "code",
604 | "execution_count": null,
605 | "metadata": {
606 | "deletable": false,
607 | "editable": false,
608 | "nbgrader": {
609 | "cell_type": "code",
610 | "checksum": "952baa82f5129893b021b87ea06c0002",
611 | "grade": true,
612 | "grade_id": "cell-e6cb93e049139151",
613 | "locked": true,
614 | "points": 1,
615 | "schema_version": 3,
616 | "solution": false,
617 | "task": false
618 | }
619 | },
620 | "outputs": [],
621 | "source": [
622 | "# This test will check whether the shop class is constrained correctly. [1 point]"
623 | ]
624 | },
625 | {
626 | "cell_type": "code",
627 | "execution_count": null,
628 | "metadata": {
629 | "deletable": false,
630 | "editable": false,
631 | "nbgrader": {
632 | "cell_type": "code",
633 | "checksum": "915b0163c5592504b56619c7845fdcf2",
634 | "grade": true,
635 | "grade_id": "cell-183716ef5c046579",
636 | "locked": true,
637 | "points": 1,
638 | "schema_version": 3,
639 | "solution": false,
640 | "task": false
641 | }
642 | },
643 | "outputs": [],
644 | "source": [
645 | "# This test will check whether you used references correctly. [1 point]"
646 | ]
647 | },
648 | {
649 | "cell_type": "code",
650 | "execution_count": null,
651 | "metadata": {
652 | "deletable": false,
653 | "editable": false,
654 | "nbgrader": {
655 | "cell_type": "code",
656 | "checksum": "1b9f936c58ca54fe9e9d4302add0e8ef",
657 | "grade": true,
658 | "grade_id": "cell-d321c676c03f079a",
659 | "locked": true,
660 | "points": 1,
661 | "schema_version": 3,
662 | "solution": false,
663 | "task": false
664 | }
665 | },
666 | "outputs": [],
667 | "source": [
668 | "# This test will check whether the product identification predicates are constrained correctly. [1 point]"
669 | ]
670 | },
671 | {
672 | "cell_type": "markdown",
673 | "metadata": {
674 | "deletable": false,
675 | "editable": false,
676 | "nbgrader": {
677 | "cell_type": "markdown",
678 | "checksum": "ebe8d0e335f4ce45391db3e1cb40688a",
679 | "grade": false,
680 | "grade_id": "cell-0ed81fa3fd2ebf99",
681 | "locked": true,
682 | "schema_version": 3,
683 | "solution": false,
684 | "task": false
685 | }
686 | },
687 | "source": [
688 | "## Inverse Triple constraints\n",
689 | "\n",
690 | "Up to now we have only constrained outgoing triples, in which the focus node is the subject of the triple. But as we will see, it can also make sense to constrain the opposite, incoming triples, in which the focus node is the object. For this one uses **inverse triple constraints** which are prefixed by a Circumflex (^). For example if we want to declare that a lecture can only be attended by students:\n",
691 | "\n",
692 | "**<LectureShape> { \n",
693 | " ex:name xsd:string ; \n",
694 | " ^ex:attends @<StudentShape> \n",
695 | "}**\n",
696 | "\n",
697 | "**<StudentShape> { \n",
698 | " ex:matNr xsd:integer MinInclusive 1 MaxInclusive 999999; \n",
699 | "}**\n",
700 | "\n",
701 | "When checking LectureShape against ex:SemWeb, the following graph will pass:\n",
702 | "\n",
703 | "**ex:SemWeb ex:name \"Semantic Web WS20\" . \n",
704 | "ex:Leia ex:attends ex:SemWeb ; \n",
705 | " ex:matNr 123456 .**\n",
706 | "\n",
707 | "but this one will fail because ex:Luke doesn't match StudentShape:\n",
708 | "\n",
709 | "**ex:SemWeb ex:name \"Semantic Web WS20\" . \n",
710 | "ex:Luke ex:attends ex:SemWeb .** \n",
711 | "\n",
712 | "## Repeated Properties\n",
713 | "\n",
714 | "Sometimes when using generic properties like ex:parent (instead of ex:father and ex:mother) they are used multiple times in one shape. We can then give them different constraints. For example, to constrain that a person has to have two parents, a male and a female one:\n",
715 | "\n",
716 | "**<PersonShape> { \n",
717 | " ex:parent @<MaleShape> ; \n",
718 | " ex:parent @<FemaleShape> \n",
719 | "}**\n",
720 | "\n",
721 | "## Closed/Open Properties\n",
722 | "\n",
723 | "Once we constrain a property in a shape, it becomes **closed**. All triples of a closed property have to match one of the constraints. Sometimes we want to constrain a property but still allow other occurrences. To do this, we have to open the property with the **EXTRA** keyword. For example, the following shape uses rdf:type as a closed property:\n",
724 | "\n",
725 | "**<InstitutionShape> { \n",
726 | " a \\[ ex:Institution \\] \n",
727 | "}**\n",
728 | "\n",
729 | "Then the following graph will fail the test against InstitutionShape because it has a second rdf:type property:\n",
730 | "\n",
731 | "**ex:RWTH a ex:Institution, ex:University .**\n",
732 | "\n",
733 | "But if we open the property rdf:type using **EXTRA \\**, the above graph will pass instead:\n",
734 | "\n",
735 | "**<InstitutionShape> EXTRA a { \n",
736 | " a \\[ ex:Institution \\] \n",
737 | "}**\n",
738 | "\n",
739 | "To open multiple properties, one does is like this:\n",
740 | "\n",
741 | "**<InstitutionShape> EXTRA ex:chair a { \n",
742 | " a \\[ ex:Institution \\] \n",
743 | "}**\n",
744 | "\n",
745 | "## Closed/Open Shapes\n",
746 | "\n",
747 | "Similar to properties, shapes can also be open/closed. By default, shapes are open, which means that additional properties not constrained in the shape are ignored by the validation. For example, the following shape is open:\n",
748 | "\n",
749 | "**<InstitutionShape> { \n",
750 | " a \\[ ex:Institution \\] \n",
751 | "}**\n",
752 | "\n",
753 | "Which means that the following graph will pass the test even though it provides additional properties for ex:RWTH:\n",
754 | "\n",
755 | "**ex:RWTH a ex:Institution ; \n",
756 | " ex:name \"Rheinisch-Westfälische Technische Hochschule Aachen\"**\n",
757 | "\n",
758 | "But if we close the shape using the **CLOSED** keyword, the above graph will instead fail the test:\n",
759 | "\n",
760 | "**<InstitutionShape> CLOSED { \n",
761 | " a \\[ ex:Institution \\] \n",
762 | "}**\n",
763 | "\n",
764 | "## Task 3: Complex Schemata [4 points]\n",
765 | "\n",
766 | "Use ShEx to model the following schema: \n",
767 | "- A team must have at least one player as a member.\n",
768 | "- A team must have exactly one coach as a member.\n",
769 | "- A team must belong to the class of groups but can additionally belong to other classes.\n",
770 | "- A team can have no other properties.\n",
771 | "\n",
772 | "The shape expression should be labelled **http://example.org/shapes#TeamShape** \n",
773 | "The shape expressions **http://example.org/shapes#PlayerShape** and **http://example.org/shapes#CoachShape** are already given. You can use them but **do not change them!**\n",
774 | "\n",
775 | "Use the following URIs: \n",
776 | "member of: **http://example.org/predicates#memberOf** \n",
777 | "Group: **http://example.org/classes#Group**"
778 | ]
779 | },
780 | {
781 | "cell_type": "code",
782 | "execution_count": null,
783 | "metadata": {
784 | "deletable": false,
785 | "nbgrader": {
786 | "cell_type": "code",
787 | "checksum": "6147505f45a4cb6ae8fb530890841b04",
788 | "grade": false,
789 | "grade_id": "cell-b472ad1ba852d38b",
790 | "locked": false,
791 | "schema_version": 3,
792 | "solution": true,
793 | "task": false
794 | }
795 | },
796 | "outputs": [],
797 | "source": [
798 | "%%rdf shex parse -l 3\n",
799 | " {\n",
800 | " a [ ] ;\n",
801 | " @ ?\n",
802 | "}\n",
803 | "\n",
804 | " {\n",
805 | " a [ ] ;\n",
806 | " @ ?\n",
807 | "}\n",
808 | "\n",
809 | "### YOUR SOLUTION HERE"
810 | ]
811 | },
812 | {
813 | "cell_type": "markdown",
814 | "metadata": {
815 | "deletable": false,
816 | "editable": false,
817 | "nbgrader": {
818 | "cell_type": "markdown",
819 | "checksum": "50c7026ecb6442dc80d4fa6dd85a9c46",
820 | "grade": false,
821 | "grade_id": "cell-fed0b294c91b167d",
822 | "locked": true,
823 | "schema_version": 3,
824 | "solution": false,
825 | "task": false
826 | }
827 | },
828 | "source": [
829 | "You can again check your answer using the two cells below."
830 | ]
831 | },
832 | {
833 | "cell_type": "code",
834 | "execution_count": null,
835 | "metadata": {
836 | "deletable": false,
837 | "editable": false,
838 | "nbgrader": {
839 | "cell_type": "code",
840 | "checksum": "980b865b52d22e274feedb32934b1232",
841 | "grade": false,
842 | "grade_id": "cell-83c6b3b5fa5eb1e4",
843 | "locked": true,
844 | "schema_version": 3,
845 | "solution": false,
846 | "task": false
847 | }
848 | },
849 | "outputs": [],
850 | "source": [
851 | "%%rdf turtle -l 3check\n",
852 | " a ;\n",
853 | " .\n",
854 | " a ;\n",
855 | " .\n",
856 | " a ;\n",
857 | " .\n",
858 | " a , ."
859 | ]
860 | },
861 | {
862 | "cell_type": "code",
863 | "execution_count": null,
864 | "metadata": {
865 | "deletable": false,
866 | "editable": false,
867 | "nbgrader": {
868 | "cell_type": "code",
869 | "checksum": "034981a38c25bee95d0a343315bd6d72",
870 | "grade": false,
871 | "grade_id": "cell-2e7c16ce6c9fba06",
872 | "locked": true,
873 | "schema_version": 3,
874 | "solution": false,
875 | "task": false
876 | }
877 | },
878 | "outputs": [],
879 | "source": [
880 | "%rdf shex validate -g 3check -l 3 -s http://example.org/shapes#TeamShape -f http://example.org/#Team"
881 | ]
882 | },
883 | {
884 | "cell_type": "code",
885 | "execution_count": null,
886 | "metadata": {
887 | "deletable": false,
888 | "editable": false,
889 | "nbgrader": {
890 | "cell_type": "code",
891 | "checksum": "a907ab2b5583068a640a6a333fb40515",
892 | "grade": true,
893 | "grade_id": "cell-812cfc2838671413",
894 | "locked": true,
895 | "points": 1,
896 | "schema_version": 3,
897 | "solution": false,
898 | "task": false
899 | }
900 | },
901 | "outputs": [],
902 | "source": [
903 | "# This test will check if modelled the first constraint correctly. [1 point]"
904 | ]
905 | },
906 | {
907 | "cell_type": "code",
908 | "execution_count": null,
909 | "metadata": {
910 | "deletable": false,
911 | "editable": false,
912 | "nbgrader": {
913 | "cell_type": "code",
914 | "checksum": "ac11867c763cf53fc53423613c038e3c",
915 | "grade": true,
916 | "grade_id": "cell-01e2d9f2766dfdfb",
917 | "locked": true,
918 | "points": 1,
919 | "schema_version": 3,
920 | "solution": false,
921 | "task": false
922 | }
923 | },
924 | "outputs": [],
925 | "source": [
926 | "# This test will check if modelled the second constraint correctly. [1 point]"
927 | ]
928 | },
929 | {
930 | "cell_type": "code",
931 | "execution_count": null,
932 | "metadata": {
933 | "deletable": false,
934 | "editable": false,
935 | "nbgrader": {
936 | "cell_type": "code",
937 | "checksum": "e755a150f707f5683e25bcc6a43d33aa",
938 | "grade": true,
939 | "grade_id": "cell-490656ec4d8e9679",
940 | "locked": true,
941 | "points": 1,
942 | "schema_version": 3,
943 | "solution": false,
944 | "task": false
945 | }
946 | },
947 | "outputs": [],
948 | "source": [
949 | "# This test will check if modelled the third constraint correctly. [1 point]"
950 | ]
951 | },
952 | {
953 | "cell_type": "code",
954 | "execution_count": null,
955 | "metadata": {
956 | "deletable": false,
957 | "editable": false,
958 | "nbgrader": {
959 | "cell_type": "code",
960 | "checksum": "5113f320e1b680f3a37872dd42b6dc00",
961 | "grade": true,
962 | "grade_id": "cell-a53d8f6ef0538b28",
963 | "locked": true,
964 | "points": 1,
965 | "schema_version": 3,
966 | "solution": false,
967 | "task": false
968 | }
969 | },
970 | "outputs": [],
971 | "source": [
972 | "# This test will check if modelled the fourth constraint correctly. [1 point]"
973 | ]
974 | },
975 | {
976 | "cell_type": "markdown",
977 | "metadata": {
978 | "deletable": false,
979 | "editable": false,
980 | "nbgrader": {
981 | "cell_type": "markdown",
982 | "checksum": "690e7ddb7ef56221416708bab2392115",
983 | "grade": false,
984 | "grade_id": "cell-33d3efd3d4fa1a25",
985 | "locked": true,
986 | "schema_version": 3,
987 | "solution": false,
988 | "task": false
989 | }
990 | },
991 | "source": [
992 | "## Task 4: Understanding Schemata [4 points]\n",
993 | "\n",
994 | "Consider the following ShEx schema:"
995 | ]
996 | },
997 | {
998 | "cell_type": "code",
999 | "execution_count": null,
1000 | "metadata": {
1001 | "deletable": false,
1002 | "editable": false,
1003 | "nbgrader": {
1004 | "cell_type": "code",
1005 | "checksum": "3ec9de6e43612ffd664074d82cc5ee84",
1006 | "grade": false,
1007 | "grade_id": "cell-59290e88062fd41d",
1008 | "locked": true,
1009 | "schema_version": 3,
1010 | "solution": false,
1011 | "task": false
1012 | }
1013 | },
1014 | "outputs": [],
1015 | "source": [
1016 | "%%rdf shex parse -l 4\n",
1017 | "PREFIX p: \n",
1018 | "PREFIX c: \n",
1019 | "PREFIX title: \n",
1020 | "PREFIX shape: \n",
1021 | "PREFIX xsd: \n",
1022 | "\n",
1023 | "shape:ExamShape CLOSED {\n",
1024 | " p:id xsd:string Length 10 AND Literal ;\n",
1025 | " p:lecture @shape:LectureShape ;\n",
1026 | " p:credit xsd:integer MinInclusive 0 MaxInclusive 12 ;\n",
1027 | " ^p:examines @shape:AssistentShape {2,} ;\n",
1028 | " ^p:examines @shape:ProfessorShape ;\n",
1029 | " ^p:attends @shape:StudentShape +\n",
1030 | "}\n",
1031 | "\n",
1032 | "shape:LectureShape CLOSED {\n",
1033 | " p:name xsd:string ;\n",
1034 | " ^p:attends @shape:StudentShape + ;\n",
1035 | "}\n",
1036 | "\n",
1037 | "shape:ProfessorShape EXTRA p:title {\n",
1038 | " p:title [ title:Professor ]\n",
1039 | "}\n",
1040 | "\n",
1041 | "shape:AssistentShape {\n",
1042 | " p:assistentOf @shape:ProfessorShape +\n",
1043 | "}\n",
1044 | "\n",
1045 | "shape:StudentShape {\n",
1046 | " p:matNr xsd:integer MinInclusive 1 MaxInclusive 999999 ;\n",
1047 | "}"
1048 | ]
1049 | },
1050 | {
1051 | "cell_type": "markdown",
1052 | "metadata": {
1053 | "deletable": false,
1054 | "editable": false,
1055 | "nbgrader": {
1056 | "cell_type": "markdown",
1057 | "checksum": "3c5e0d315dc2058b13e5a51bcbb65a4a",
1058 | "grade": false,
1059 | "grade_id": "cell-4e3a79fd3cb63c13",
1060 | "locked": true,
1061 | "schema_version": 3,
1062 | "solution": false,
1063 | "task": false
1064 | }
1065 | },
1066 | "source": [
1067 | "Model a graph using turtle which passes when tested against the above schema.\n",
1068 | "\n",
1069 | "The validation will start at **http://example.org/shapes#ExamShape** and will focus on the node **http://example.org/#SemWebExam**"
1070 | ]
1071 | },
1072 | {
1073 | "cell_type": "code",
1074 | "execution_count": null,
1075 | "metadata": {
1076 | "deletable": false,
1077 | "nbgrader": {
1078 | "cell_type": "code",
1079 | "checksum": "60be3bf6b8f1105c45faa9801ffb7159",
1080 | "grade": false,
1081 | "grade_id": "cell-b4ea49e66ee714e0",
1082 | "locked": false,
1083 | "schema_version": 3,
1084 | "solution": true,
1085 | "task": false
1086 | }
1087 | },
1088 | "outputs": [],
1089 | "source": [
1090 | "%%rdf turtle -l 4 -d graph\n",
1091 | "### YOUR SOLUTION HERE"
1092 | ]
1093 | },
1094 | {
1095 | "cell_type": "markdown",
1096 | "metadata": {
1097 | "deletable": false,
1098 | "editable": false,
1099 | "nbgrader": {
1100 | "cell_type": "markdown",
1101 | "checksum": "9fc94bd1b51f4aec3cbe67db79c2f048",
1102 | "grade": false,
1103 | "grade_id": "cell-8edbdecfe5f8b27a",
1104 | "locked": true,
1105 | "schema_version": 3,
1106 | "solution": false,
1107 | "task": false
1108 | }
1109 | },
1110 | "source": [
1111 | "You can check whether your graph passes by running the cell below. If it doesn't pass, the validator will give you a hint and if it passes you will get all points!"
1112 | ]
1113 | },
1114 | {
1115 | "cell_type": "code",
1116 | "execution_count": null,
1117 | "metadata": {
1118 | "deletable": false,
1119 | "editable": false,
1120 | "nbgrader": {
1121 | "cell_type": "code",
1122 | "checksum": "83f59c4aa25bda049231ddeb5dcd05bb",
1123 | "grade": false,
1124 | "grade_id": "cell-f93fff27083a858d",
1125 | "locked": true,
1126 | "schema_version": 3,
1127 | "solution": false,
1128 | "task": false
1129 | }
1130 | },
1131 | "outputs": [],
1132 | "source": [
1133 | "%rdf shex validate -l 4 -g 4 -s http://example.org/shapes#ExamShape -f http://example.org/#SemWebExam"
1134 | ]
1135 | },
1136 | {
1137 | "cell_type": "code",
1138 | "execution_count": null,
1139 | "metadata": {
1140 | "deletable": false,
1141 | "editable": false,
1142 | "nbgrader": {
1143 | "cell_type": "code",
1144 | "checksum": "adaac48a0f7de9fae548e9c944f371b6",
1145 | "grade": true,
1146 | "grade_id": "cell-b457d9b4f1050549",
1147 | "locked": true,
1148 | "points": 4,
1149 | "schema_version": 3,
1150 | "solution": false,
1151 | "task": false
1152 | }
1153 | },
1154 | "outputs": [],
1155 | "source": [
1156 | "# This test will check whether your graph passes the validation. [4 points]"
1157 | ]
1158 | }
1159 | ],
1160 | "metadata": {
1161 | "kernelspec": {
1162 | "display_name": "Python 3",
1163 | "language": "python",
1164 | "name": "python3"
1165 | },
1166 | "language_info": {
1167 | "codemirror_mode": {
1168 | "name": "ipython",
1169 | "version": 3
1170 | },
1171 | "file_extension": ".py",
1172 | "mimetype": "text/x-python",
1173 | "name": "python",
1174 | "nbconvert_exporter": "python",
1175 | "pygments_lexer": "ipython3",
1176 | "version": "3.8.5"
1177 | }
1178 | },
1179 | "nbformat": 4,
1180 | "nbformat_minor": 4
1181 | }
1182 |
--------------------------------------------------------------------------------
/Notebooks/SemWebEx6.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "deletable": false,
8 | "editable": false,
9 | "nbgrader": {
10 | "cell_type": "code",
11 | "checksum": "dcf5ac2ab7403387060a47fd9ccff088",
12 | "grade": false,
13 | "grade_id": "cell-80aba36ab7e1e364",
14 | "locked": true,
15 | "schema_version": 3,
16 | "solution": false,
17 | "task": false
18 | }
19 | },
20 | "outputs": [],
21 | "source": [
22 | "%reload_ext jupyter-rdfify"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": null,
28 | "metadata": {
29 | "deletable": false,
30 | "editable": false,
31 | "nbgrader": {
32 | "cell_type": "code",
33 | "checksum": "815dd810a9958e8fb12f0b31a5275c16",
34 | "grade": true,
35 | "grade_id": "cell-f85fc016a4803480",
36 | "locked": true,
37 | "points": 0,
38 | "schema_version": 3,
39 | "solution": false,
40 | "task": false
41 | }
42 | },
43 | "outputs": [],
44 | "source": [
45 | "# This is a placeholder cell for test initialization. Ignore it."
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {
51 | "deletable": false,
52 | "editable": false,
53 | "nbgrader": {
54 | "cell_type": "markdown",
55 | "checksum": "f39fafb34d8c688f4d265bf65ef3dcac",
56 | "grade": false,
57 | "grade_id": "cell-4dfd48987044ad74",
58 | "locked": true,
59 | "schema_version": 3,
60 | "solution": false,
61 | "task": false
62 | }
63 | },
64 | "source": [
65 | "**This is a bonus sheet. The points you acquire in this sheet will count towards your exam admission but the sheet will not affect the total needed for the admission. Even if you already have your admission, we highly recommend working on this sheet as its content is relevant for the exam.**\n",
66 | "\n",
67 | "**If you have never worked with JSON before, it is highly recommended to learn it before working with JSON-LD. It is a very simple format and nicely explained [here](https://www.json.org/json-en.html).**\n",
68 | "\n",
69 | "The extension will treat everything on a line after \"###\" as comment but this is **not** JSON syntax!\n",
70 | "\n",
71 | "**Only edit cells with \"### YOUR SOLUTION HERE\". Any points lost because other cells were edited will not be restored.**"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {
77 | "deletable": false,
78 | "editable": false,
79 | "nbgrader": {
80 | "cell_type": "markdown",
81 | "checksum": "3f535e894e7e86f3d92802bd3678dee1",
82 | "grade": false,
83 | "grade_id": "cell-296d0c2c44ab4f83",
84 | "locked": true,
85 | "schema_version": 3,
86 | "solution": false,
87 | "task": false
88 | }
89 | },
90 | "source": [
91 | "## Reminder: Prefixes\n",
92 | "\n",
93 | "As there was a lot of confusion concerning prefixes and CURIEs in the last exercises, here is a small reminder to prevent further errors.\n",
94 | "\n",
95 | "Let's say we have the three URIs <http://example.org/#Rick>, <http://example.org/#Morty> and <http://example.org/#Character>. Now we can use them in a Turtle graph as is:\n",
96 | "\n",
97 | "**<http://example.org/#Rick> a <http://example.org/#Character> . \n",
98 | "<http://example.org/#Morty> a <http://example.org/#Character> .**\n",
99 | "\n",
100 | "This is hard to read and has a lot of repetition. As all three URIs begin with <http://example.org/#>, we can abbreviate them using prefixes. So we define a prefix and label it **ex:**. This gives us a much more readable graph:\n",
101 | "\n",
102 | "**PREFIX ex: <http://example.org/#> \n",
103 | "ex:Rick a ex:Character . \n",
104 | "ex:Morty a ex:Character .**\n",
105 | "\n",
106 | "**Some tips:**\n",
107 | "- **Try to always define them by hand. There were a lot of errors caused by copy and pasting wrong prefixes.**\n",
108 | "- **Check for typos! URIs are case sensitive and the tests only pass for an exact match.**\n",
109 | "- **The pound symbol (#) is part of the URI! <http://example.org/Rick> and <http://example.org/#Rick> are completely different URIs.**\n",
110 | "- **Prefixes do not change the graph! You don't have to use them if you don't want to.**\n",
111 | "\n",
112 | "**The cell below will define some prefixes which you may use in this entire sheet. Please note that these will only work in Turtle.**"
113 | ]
114 | },
115 | {
116 | "cell_type": "code",
117 | "execution_count": null,
118 | "metadata": {
119 | "deletable": false,
120 | "editable": false,
121 | "nbgrader": {
122 | "cell_type": "code",
123 | "checksum": "4d8e2e712b18e618102b2904d2898b71",
124 | "grade": false,
125 | "grade_id": "cell-eeda6742ff20a244",
126 | "locked": true,
127 | "schema_version": 3,
128 | "solution": false,
129 | "task": false
130 | }
131 | },
132 | "outputs": [],
133 | "source": [
134 | "%%rdf turtle --prefix\n",
135 | "PREFIX xsd: "
136 | ]
137 | },
138 | {
139 | "cell_type": "markdown",
140 | "metadata": {
141 | "deletable": false,
142 | "editable": false,
143 | "nbgrader": {
144 | "cell_type": "markdown",
145 | "checksum": "f1be93687f5a176a953e226a56b7ebbf",
146 | "grade": false,
147 | "grade_id": "cell-116cd86dbcb6e858",
148 | "locked": true,
149 | "schema_version": 3,
150 | "solution": false,
151 | "task": false
152 | }
153 | },
154 | "source": [
155 | "# JSON-LD\n",
156 | "\n",
157 | "JSON-LD is a W3C recommended RDF graph serialization format. It uses the wide spread JavaScript Object Notation (JSON) format.\n",
158 | "\n",
159 | "For more information on JSON-LD please consult the lecture slides (Linked Data Basics, Lecture 2b) or the [JSON-LD W3C recommendation](https://www.w3.org/TR/json-ld/)\n",
160 | "\n",
161 | "## Task 1: Understanding JSON-LD [3 points]\n",
162 | "Consider the following RDF graph in JSON-LD format (run the cell to get a visualisation):"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": null,
168 | "metadata": {
169 | "deletable": false,
170 | "editable": false,
171 | "nbgrader": {
172 | "cell_type": "code",
173 | "checksum": "dc4a2a43469d3920582d36d34fb5461a",
174 | "grade": false,
175 | "grade_id": "cell-2a975b3779244fac",
176 | "locked": true,
177 | "schema_version": 3,
178 | "solution": false,
179 | "task": false
180 | }
181 | },
182 | "outputs": [],
183 | "source": [
184 | "%%rdf json-ld -d graph\n",
185 | "{\n",
186 | " \"@context\": {\n",
187 | " \"ex\": \"http://example.org/shops#\",\n",
188 | " \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n",
189 | " },\n",
190 | " \"@id\": \"ex:eBuy\",\n",
191 | " \"@type\": \"ex:OnlineShop\",\n",
192 | " \"ex:name\": {\n",
193 | " \"@value\": \"eBuy\",\n",
194 | " \"@language\": \"en\"\n",
195 | " },\n",
196 | " \"ex:products\": {\n",
197 | " \"@list\": [\n",
198 | " \"Toilet paper\",\n",
199 | " \"Disinfectant\",\n",
200 | " \"Masks\"\n",
201 | " ]\n",
202 | " },\n",
203 | " \"ex:competitor\": {\n",
204 | " \"@id\": \"ex:Emazon\",\n",
205 | " \"@type\": \"ex:OnlineShop\",\n",
206 | " \"ex:name\": \"Emazon\",\n",
207 | " \"ex:subscriptionService\": [\n",
208 | " \"Emazon Prime\",\n",
209 | " \"Emazon Prime Video\"\n",
210 | " ]\n",
211 | " }\n",
212 | "}"
213 | ]
214 | },
215 | {
216 | "cell_type": "markdown",
217 | "metadata": {
218 | "deletable": false,
219 | "editable": false,
220 | "nbgrader": {
221 | "cell_type": "markdown",
222 | "checksum": "2c74d3fc5fcef3636bd862c0bc8ab5e6",
223 | "grade": false,
224 | "grade_id": "cell-d19855b1f9e78205",
225 | "locked": true,
226 | "schema_version": 3,
227 | "solution": false,
228 | "task": false
229 | }
230 | },
231 | "source": [
232 | "Create an identical graph using Turtle notation in the cell below.\n",
233 | "\n",
234 | "**Please make sure that your prefixes are correct.** \n",
235 | "**Tip: Run the cell and compare the graphs. They should be identical up to prefix renaming.**"
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "execution_count": null,
241 | "metadata": {
242 | "deletable": false,
243 | "nbgrader": {
244 | "cell_type": "code",
245 | "checksum": "1a66b9bf1cdb6c9f1e355edfbc2dc051",
246 | "grade": false,
247 | "grade_id": "cell-e3c6c8d1a45ecf7d",
248 | "locked": false,
249 | "schema_version": 3,
250 | "solution": true,
251 | "task": false
252 | }
253 | },
254 | "outputs": [],
255 | "source": [
256 | "%%rdf turtle -d graph -l shops\n",
257 | "### YOUR SOLUTION HERE"
258 | ]
259 | },
260 | {
261 | "cell_type": "code",
262 | "execution_count": null,
263 | "metadata": {
264 | "deletable": false,
265 | "editable": false,
266 | "nbgrader": {
267 | "cell_type": "code",
268 | "checksum": "ad4fb9c74c78310daf3c9947641f93c5",
269 | "grade": true,
270 | "grade_id": "cell-61448fca0d54cd95",
271 | "locked": true,
272 | "points": 1.5,
273 | "schema_version": 3,
274 | "solution": false,
275 | "task": false
276 | }
277 | },
278 | "outputs": [],
279 | "source": [
280 | "# This test will check whether you modelled eBuy correctly [1.5 points]"
281 | ]
282 | },
283 | {
284 | "cell_type": "code",
285 | "execution_count": null,
286 | "metadata": {
287 | "deletable": false,
288 | "editable": false,
289 | "nbgrader": {
290 | "cell_type": "code",
291 | "checksum": "acb85680498eb2f547ee175cfeb1d068",
292 | "grade": true,
293 | "grade_id": "cell-572010cc326d8c1b",
294 | "locked": true,
295 | "points": 1.5,
296 | "schema_version": 3,
297 | "solution": false,
298 | "task": false
299 | }
300 | },
301 | "outputs": [],
302 | "source": [
303 | "# This test will check whether you modelled Emazon correctly [1.5 points]"
304 | ]
305 | },
306 | {
307 | "cell_type": "markdown",
308 | "metadata": {
309 | "deletable": false,
310 | "editable": false,
311 | "nbgrader": {
312 | "cell_type": "markdown",
313 | "checksum": "40e84a520c8537880dc7922cc6c98977",
314 | "grade": false,
315 | "grade_id": "cell-4bcc34dfe90bb260",
316 | "locked": true,
317 | "schema_version": 3,
318 | "solution": false,
319 | "task": false
320 | }
321 | },
322 | "source": [
323 | "## Task 2: JSON-LD Person [4 points]\n",
324 | "\n",
325 | "Consider the following RDF graph in Turtle format:"
326 | ]
327 | },
328 | {
329 | "cell_type": "code",
330 | "execution_count": null,
331 | "metadata": {
332 | "deletable": false,
333 | "editable": false,
334 | "nbgrader": {
335 | "cell_type": "code",
336 | "checksum": "93d88dd55b3261f5ed5e142b79329e76",
337 | "grade": false,
338 | "grade_id": "cell-cb50ba84d893cf56",
339 | "locked": true,
340 | "schema_version": 3,
341 | "solution": false,
342 | "task": false
343 | }
344 | },
345 | "outputs": [],
346 | "source": [
347 | "%%rdf turtle -d graph\n",
348 | "PREFIX rdf: \n",
349 | "PREFIX xsd: \n",
350 | "PREFIX ex: \n",
351 | "\n",
352 | "ex:Michael a ex:Person ;\n",
353 | " ex:name \"Michael Scott\" ;\n",
354 | " ex:job ex:RegionalManager ;\n",
355 | " ex:phoneNumber \"012346789\" ;\n",
356 | " ex:age \"44\"^^xsd:integer ;\n",
357 | " ex:friends (ex:Jim ex:Pam ex:Dwight) ."
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "metadata": {
363 | "deletable": false,
364 | "editable": false,
365 | "nbgrader": {
366 | "cell_type": "markdown",
367 | "checksum": "00bb1684a23b0281732a0d0ced5d1911",
368 | "grade": false,
369 | "grade_id": "cell-aaf037d37e5e84ad",
370 | "locked": true,
371 | "schema_version": 3,
372 | "solution": false,
373 | "task": false
374 | }
375 | },
376 | "source": [
377 | "Create the same graph using JSON-LD. \n",
378 | "**Please note the difference between URIs and literals e.g. ex:Professor vs \"ex:Professor\"**"
379 | ]
380 | },
381 | {
382 | "cell_type": "code",
383 | "execution_count": null,
384 | "metadata": {
385 | "deletable": false,
386 | "nbgrader": {
387 | "cell_type": "code",
388 | "checksum": "0afaa71115efc3f1b1745c4a5a66526d",
389 | "grade": false,
390 | "grade_id": "cell-3a92dab72bf7e251",
391 | "locked": false,
392 | "schema_version": 3,
393 | "solution": true,
394 | "task": false
395 | }
396 | },
397 | "outputs": [],
398 | "source": [
399 | "%%rdf json-ld -d graph -l office\n",
400 | "{\n",
401 | " ### YOUR SOLUTION HERE\n",
402 | "}"
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": null,
408 | "metadata": {
409 | "deletable": false,
410 | "editable": false,
411 | "nbgrader": {
412 | "cell_type": "code",
413 | "checksum": "19918e66a6e75aee07eb48eeb9ef38e3",
414 | "grade": true,
415 | "grade_id": "cell-0d6d9e590d485fbd",
416 | "locked": true,
417 | "points": 1,
418 | "schema_version": 3,
419 | "solution": false,
420 | "task": false
421 | }
422 | },
423 | "outputs": [],
424 | "source": [
425 | "# This test will check whether your node has the correct type. [1 point]"
426 | ]
427 | },
428 | {
429 | "cell_type": "code",
430 | "execution_count": null,
431 | "metadata": {
432 | "deletable": false,
433 | "editable": false,
434 | "nbgrader": {
435 | "cell_type": "code",
436 | "checksum": "ffc33af5ce12688196f77cc49e72e341",
437 | "grade": true,
438 | "grade_id": "cell-e8b4b924718268e1",
439 | "locked": true,
440 | "points": 1,
441 | "schema_version": 3,
442 | "solution": false,
443 | "task": false
444 | }
445 | },
446 | "outputs": [],
447 | "source": [
448 | "# This test will check whether your literals are correct. [1 point]"
449 | ]
450 | },
451 | {
452 | "cell_type": "code",
453 | "execution_count": null,
454 | "metadata": {
455 | "deletable": false,
456 | "editable": false,
457 | "nbgrader": {
458 | "cell_type": "code",
459 | "checksum": "47f7c24878eae235218f113f9d5b0109",
460 | "grade": true,
461 | "grade_id": "cell-004a89c6d830b5e6",
462 | "locked": true,
463 | "points": 1,
464 | "schema_version": 3,
465 | "solution": false,
466 | "task": false
467 | }
468 | },
469 | "outputs": [],
470 | "source": [
471 | "# This test will check whether your friendlist is correct. [1 point]"
472 | ]
473 | },
474 | {
475 | "cell_type": "code",
476 | "execution_count": null,
477 | "metadata": {
478 | "deletable": false,
479 | "editable": false,
480 | "nbgrader": {
481 | "cell_type": "code",
482 | "checksum": "3aea0e88bbf4e78fa26cf79c50c58954",
483 | "grade": true,
484 | "grade_id": "cell-73e1bd61abbd1e5a",
485 | "locked": true,
486 | "points": 1,
487 | "schema_version": 3,
488 | "solution": false,
489 | "task": false
490 | }
491 | },
492 | "outputs": [],
493 | "source": [
494 | "# This test will check whether your other triples are correct. [1 point]"
495 | ]
496 | },
497 | {
498 | "cell_type": "markdown",
499 | "metadata": {
500 | "deletable": false,
501 | "editable": false,
502 | "nbgrader": {
503 | "cell_type": "markdown",
504 | "checksum": "b7cce3caa7ff73b78a44a2e4b0b967f2",
505 | "grade": false,
506 | "grade_id": "cell-07971b190da8ba1b",
507 | "locked": true,
508 | "schema_version": 3,
509 | "solution": false,
510 | "task": false
511 | }
512 | },
513 | "source": [
514 | "## Task 3: Blank Nodes & Reification [2 points]\n",
515 | "Model the following in JSON-LD using RDF reification.\n",
516 | "\n",
517 | "Peralta knows that Terry loves joghurt.\n",
518 | "\n",
519 | "Use the following URIs: \n",
520 | "Peralta: **http://example.org/#Peralta** \n",
521 | "knows: **http://example.org/#knows** \n",
522 | "Terry: **http://example.org/#Terry** \n",
523 | "loves: **http://example.org/#loves** \n",
524 | "Joghurt: **http://example.org/#Joghurt** \n",
525 | "\n",
526 | "You may need the RDF vocabulary prefix: **http://www.w3.org/1999/02/22-rdf-syntax-ns#**"
527 | ]
528 | },
529 | {
530 | "cell_type": "code",
531 | "execution_count": null,
532 | "metadata": {
533 | "deletable": false,
534 | "nbgrader": {
535 | "cell_type": "code",
536 | "checksum": "d715e40d4aa120f359615e5d21064ec4",
537 | "grade": false,
538 | "grade_id": "cell-5a05214e22fc1331",
539 | "locked": false,
540 | "schema_version": 3,
541 | "solution": true,
542 | "task": false
543 | }
544 | },
545 | "outputs": [],
546 | "source": [
547 | "%%rdf json-ld -d graph -l 99\n",
548 | "{\n",
549 | " ### YOUR SOLUTION HERE\n",
550 | "}"
551 | ]
552 | },
553 | {
554 | "cell_type": "code",
555 | "execution_count": null,
556 | "metadata": {
557 | "deletable": false,
558 | "editable": false,
559 | "nbgrader": {
560 | "cell_type": "code",
561 | "checksum": "634e572c5b6a8004ec8cef0634e9382d",
562 | "grade": true,
563 | "grade_id": "cell-2578225ee82a3eac",
564 | "locked": true,
565 | "points": 1,
566 | "schema_version": 3,
567 | "solution": false,
568 | "task": false
569 | }
570 | },
571 | "outputs": [],
572 | "source": [
573 | "# This test will check whether you modelled the blank node correctly. [1 point]"
574 | ]
575 | },
576 | {
577 | "cell_type": "code",
578 | "execution_count": null,
579 | "metadata": {
580 | "deletable": false,
581 | "editable": false,
582 | "nbgrader": {
583 | "cell_type": "code",
584 | "checksum": "dbab91479023f7e6146a9d6c5962dbc4",
585 | "grade": true,
586 | "grade_id": "cell-81792a90cfa7f7a7",
587 | "locked": true,
588 | "points": 1,
589 | "schema_version": 3,
590 | "solution": false,
591 | "task": false
592 | }
593 | },
594 | "outputs": [],
595 | "source": [
596 | "# This test will check whether you modelled the reification correctly. [1 point]"
597 | ]
598 | },
599 | {
600 | "cell_type": "markdown",
601 | "metadata": {
602 | "deletable": false,
603 | "editable": false,
604 | "nbgrader": {
605 | "cell_type": "markdown",
606 | "checksum": "f5f3a7282993fb48c8d10282e3abe34c",
607 | "grade": false,
608 | "grade_id": "cell-0965fcf39f7df5e9",
609 | "locked": true,
610 | "schema_version": 3,
611 | "solution": false,
612 | "task": false
613 | }
614 | },
615 | "source": [
616 | "## Task 4: Multiple Graphs, Multiple Properties And Multiple Languages [3 points]\n",
617 | "Consider the following RDF graph in Turtle format:"
618 | ]
619 | },
620 | {
621 | "cell_type": "code",
622 | "execution_count": null,
623 | "metadata": {
624 | "deletable": false,
625 | "editable": false,
626 | "nbgrader": {
627 | "cell_type": "code",
628 | "checksum": "5575dc026ec83525d8465511afb7749e",
629 | "grade": false,
630 | "grade_id": "cell-d9ab69936cfb71e2",
631 | "locked": true,
632 | "schema_version": 3,
633 | "solution": false,
634 | "task": false
635 | }
636 | },
637 | "outputs": [],
638 | "source": [
639 | "%%rdf turtle -d graph\n",
640 | "PREFIX rdf: \n",
641 | "PREFIX xsd: \n",
642 | "PREFIX ex: \n",
643 | "\n",
644 | "ex:Germany ex:name \"Deutschland\"@de, \"Germany\"@en .\n",
645 | "ex:Sweden ex:name \"Schweden\"@de, \"Sweden\"@en ."
646 | ]
647 | },
648 | {
649 | "cell_type": "markdown",
650 | "metadata": {
651 | "deletable": false,
652 | "editable": false,
653 | "nbgrader": {
654 | "cell_type": "markdown",
655 | "checksum": "fcdda475a36fe461c19b8e54748308b9",
656 | "grade": false,
657 | "grade_id": "cell-f4b59ad9c2b853cf",
658 | "locked": true,
659 | "schema_version": 3,
660 | "solution": false,
661 | "task": false
662 | }
663 | },
664 | "source": [
665 | "Create an identical graph using JSON-LD."
666 | ]
667 | },
668 | {
669 | "cell_type": "code",
670 | "execution_count": null,
671 | "metadata": {
672 | "deletable": false,
673 | "nbgrader": {
674 | "cell_type": "code",
675 | "checksum": "390a9703c0f7c8d244c0edbd1865a9b9",
676 | "grade": false,
677 | "grade_id": "cell-7ac50fae9fadd1b9",
678 | "locked": false,
679 | "schema_version": 3,
680 | "solution": true,
681 | "task": false
682 | }
683 | },
684 | "outputs": [],
685 | "source": [
686 | "%%rdf json-ld -d graph -l multi\n",
687 | "{\n",
688 | " ### YOUR SOLUTION HERE\n",
689 | "}"
690 | ]
691 | },
692 | {
693 | "cell_type": "code",
694 | "execution_count": null,
695 | "metadata": {
696 | "deletable": false,
697 | "editable": false,
698 | "nbgrader": {
699 | "cell_type": "code",
700 | "checksum": "04285120dc5a14a88cfe547ab2549bff",
701 | "grade": true,
702 | "grade_id": "cell-bed0298d85eea115",
703 | "locked": true,
704 | "points": 1,
705 | "schema_version": 3,
706 | "solution": false,
707 | "task": false
708 | }
709 | },
710 | "outputs": [],
711 | "source": [
712 | "# This test will check whether you modelled multiple disconnected graphs. [1 point]"
713 | ]
714 | },
715 | {
716 | "cell_type": "code",
717 | "execution_count": null,
718 | "metadata": {
719 | "deletable": false,
720 | "editable": false,
721 | "nbgrader": {
722 | "cell_type": "code",
723 | "checksum": "0d289456ec8db854ab448c3d03137546",
724 | "grade": true,
725 | "grade_id": "cell-a6bc899633d4619e",
726 | "locked": true,
727 | "points": 1,
728 | "schema_version": 3,
729 | "solution": false,
730 | "task": false
731 | }
732 | },
733 | "outputs": [],
734 | "source": [
735 | "# This test will check whether you modelled multiple name properties correctly. [1 point]"
736 | ]
737 | },
738 | {
739 | "cell_type": "code",
740 | "execution_count": null,
741 | "metadata": {
742 | "deletable": false,
743 | "editable": false,
744 | "nbgrader": {
745 | "cell_type": "code",
746 | "checksum": "eb43b1b34b442dd0b1f1c7d2b3864a1e",
747 | "grade": true,
748 | "grade_id": "cell-9a7ddad3954864b5",
749 | "locked": true,
750 | "points": 1,
751 | "schema_version": 3,
752 | "solution": false,
753 | "task": false
754 | }
755 | },
756 | "outputs": [],
757 | "source": [
758 | "# This test will check whether you modelled multiple languages correctly. [1 point]"
759 | ]
760 | }
761 | ],
762 | "metadata": {
763 | "kernelspec": {
764 | "display_name": "Python 3",
765 | "language": "python",
766 | "name": "python3"
767 | },
768 | "language_info": {
769 | "codemirror_mode": {
770 | "name": "ipython",
771 | "version": 3
772 | },
773 | "file_extension": ".py",
774 | "mimetype": "text/x-python",
775 | "name": "python",
776 | "nbconvert_exporter": "python",
777 | "pygments_lexer": "ipython3",
778 | "version": "3.8.5"
779 | }
780 | },
781 | "nbformat": 4,
782 | "nbformat_minor": 4
783 | }
784 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jupyter Notebooks for Teaching Semantic Web Technologies
2 |
3 | This repository contains the digital learning materials, scripts and documents employed by the [Chair of Information Systems at RWTH Aachen University](http://dbis.rwth-aachen.de/) to interactively teach Semantic Web Lectures with IPython Jupyter Notebooks.
4 |
5 | All notebooks are developed based on [Jupyter-RDFify](https://github.com/SemWebNotebooks/Jupyter-RDFify), our IPython plugin bringing support for Semantic Web Technologies, such as Turtle, SPARQL, ShEx, etc., directly into the Jupyter Notebook ecosystem.
6 |
7 | ## Try It Yourself!
8 |
9 | Start a Jupyter Notebook server and follow the instructions given in the [example notebook](Notebooks/Jupyter-RDFify-Example.ipynb) to install the dependencies and get a feature overview.
10 |
11 | Don't have a Jupyter Notebook server installed? You can open the example notebook right now in your browser using binder by clicking on the badge below.
12 |
13 | [](https://mybinder.org/v2/gh/SemWebNotebooks/Notebooks/HEAD?filepath=Notebooks%2FJupyter-RDFify-Example.ipynb)
14 |
15 | ## Contents
16 |
17 | File or path | Description
18 | --- | ---
19 | [workflow.pdf](Docs/Workflow/workflow.pdf) | A document describing the process of creating a jupyter notebook assignment and automatically grading it.
20 | [SemWeb_jupyter_guide.pdf](Docs/SemWeb_jupyter_guide/SemWeb_jupyter_guide.pdf) | A document to teach students how to use JupyterHub or a local installation of Jupyter to open notebooks.
21 | [Notebooks](Notebooks/) | This path contains the **student versions** of the SemWebNotebooks, which do **not** include the unit tests used for automatic grading. Please contact `semweb [at] dbis (dot) rwth-aachen {dot} de` if you want to get a copy the full notebooks.
22 | [moodle_nbgrader](Scripts/moodle_nbgrader) | This is a very slightly changed fork of [moodle_nbgrader by johnhw](https://github.com/johnhw/moodle_nbgrader). These are scripts used to change the moodle submission directory structure to the nbgrader directory structure.
23 | [snippets](Scripts/snippets) | For code snippets used in notebooks or elsewhere.
24 | [Evaluation](Evaluation.ipynb) | A quantitative summary of the [raw evaluation results](Eval_semweb_tool.xlsx) of our user study.
25 |
26 | ## Submodules & Libs
27 |
28 | RDFLib: https://rdflib.readthedocs.io/en/stable/
29 |
30 | RDFLib-jsonld: https://github.com/RDFLib/rdflib-jsonld
31 |
32 | OWL-RL: https://owl-rl.readthedocs.io/en/latest/
33 |
34 | Graphviz: https://graphviz.org
35 |
--------------------------------------------------------------------------------
/Scripts/moodle_nbgrader/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Scripts/moodle_nbgrader/README.md:
--------------------------------------------------------------------------------
1 | This is a very slightly changed fork of [moodle_nbgrader by johnhw](https://github.com/johnhw/moodle_nbgrader).
2 |
3 | ## Submissions
4 | Assuming you have an assignment called `` (e.g. `week_2_numerical_ii`)
5 |
6 | 1. From Moodle, select assignment
7 | 2. `View All Submissions`
8 | 3. `Reveal student identities`
9 | 4. Choose `Download All Submissions` from top dropdown (MAKE SURE `Download submissions in folders` is OFF)
10 | 5. Copy archive to `imports/.zip`
11 | 6. Choose `Download grading worksheet`
12 | 5. Copy CSV to `imports/.csv`
13 |
14 | python collect_files.py
15 |
16 | Example:
17 |
18 | python collect_files.py week_2_numerical_ii lab_2
19 |
20 |
21 | Run:
22 |
23 | nbgrader autograde
24 |
25 | to grade the files
26 |
27 | Then run:
28 |
29 | python update_gradesheet.py
30 |
31 | This will produce:
32 | * `exports/.csv` for upload as `Upload grading worksheet`
33 | * `exports/_feedback.zip` for upload as `Upload multiple feedback files as zip`
34 |
35 |
36 | ## Creating assignments
37 | 1. in Moodle, enable offline gradebook and feedback files in the assignment
38 | 1. Create assignment in formgrader
39 | 2. Edit assignment and validate
40 | 3. Hit "Generate" in formgrader
41 | 4. Or use `nbgrader assign --force`
42 | 5. `python release_zip.py ` to generate the zip file in `uploads`
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Scripts/moodle_nbgrader/collect_files.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import nbgrader, csv, codecs, sys, os, shutil
4 | from nbgrader.apps import NbGraderAPI
5 | import zipfile
6 | import shutil
7 | verbose = False
8 |
9 | def moodle_gradesheet(notebook_name, assign_name, csvfile, zip):
10 |
11 | api = NbGraderAPI()
12 | gradebook = api.gradebook
13 |
14 |
15 | archive = zipfile.ZipFile(zip)
16 | fnames = {}
17 |
18 | # read all the filenames, and get the submission
19 | # ids for each filename
20 | for f in archive.filelist:
21 | fname = f.filename
22 | match = re.match("[\*\w\-\'\s\.\,]+_([0-9]+)_.*", fname)
23 | if match:
24 | fnames[match.groups()[0]] = fname
25 | else:
26 | print("Did not match ", fname)
27 |
28 | with open(csvfile, newline='', encoding='utf-8-sig') as f:
29 | reader = csv.DictReader(f)
30 | assign_matric = {}
31 | n_rows = 0
32 | successful_files = 0
33 | missing_files = 0
34 | problem_files = 0
35 |
36 | for line in reader:
37 |
38 | ident, fullname,email, status, grade, max_grade = (line['Identifier'], line['Full name'], line["Registration number"],
39 | line['Status'], line['Grade'], line['Maximum Grade'])
40 |
41 | should_be_submission = "Submitted" in status
42 |
43 | # make sure we have this student in our records
44 | unique_id = email[0:7]
45 | try:
46 | result = gradebook.find_student(unique_id)
47 | except nbgrader.api.MissingEntry:
48 | print("Creating gradebook entry for ", unique_id)
49 | gradebook.update_or_create_student(unique_id, first_name=fullname, last_name="", email=email)
50 |
51 |
52 | # map assignment numbers to matric numbers
53 | matric = email[0:7]
54 | match = re.match('Participant ([0-9]+)', ident)
55 | if not match:
56 | print(f"Could not find identity for participant {ident}")
57 | continue
58 |
59 | ident = match.groups()[0]
60 | assign_matric[ident] = matric
61 |
62 | n_rows += 1
63 | if ident in fnames:
64 | # extract each file to the submission directory
65 | submission_path = os.path.join("submitted", matric, assign_name)
66 | try:
67 | os.makedirs(submission_path)
68 | except:
69 | pass
70 | fname = fnames[ident]
71 | notebook_file = os.path.basename(fname)
72 | notebook_file = notebook_name+".ipynb"
73 | if verbose:
74 | print("Extracting {notebook} to {path}".format(notebook=notebook_file, path=submission_path))
75 |
76 | source = archive.open(fname)
77 | target = open(os.path.join(submission_path, notebook_file), "wb")
78 | with source, target:
79 | shutil.copyfileobj(source, target)
80 |
81 | successful_files += 1
82 | else:
83 | # submission was in the CSV file, but we don't have a zip file
84 | if should_be_submission:
85 | print("*** WARNING! No submission for", fullname, matric, "but submission status was", status, "***")
86 | problem_files += 1
87 | else:
88 | # submission was not listed in the CSV file as being submitted
89 | if verbose:
90 | print("No submission for ", fullname, matric, status, "as expected")
91 | missing_files +=1
92 |
93 | # print out a summary of what was processed
94 | print("""{n_files:d} succesfully extracted of {total_zip:d} files in the ZIP archive.
95 | {missing:d} files were not submitted, as expected.
96 | {problem:d} files were missing, but showed as submitted on Moodle.
97 | {total:d} records were processed, and {total_csv} rows in the CSV.
98 | """.format(n_files=successful_files, missing=missing_files, problem=problem_files,
99 | total=successful_files+missing_files+problem_files,
100 | total_zip = len(fnames), total_csv=n_rows))
101 |
102 |
103 |
104 | import sys
105 |
106 | if len(sys.argv)!=3:
107 | print("""
108 | Usage:
109 |
110 | collect_files.py
111 |
112 | # must have the following files in imports/
113 |
114 | .csv .zip
115 |
116 | The results will be copied into submitted///submission.ipynb
117 |
118 | """)
119 | sys.exit()
120 |
121 |
122 | assign_name, notebook_name = sys.argv[1], sys.argv[2]
123 | gradesheet_csv, archive_fname = os.path.join("imports", assign_name+".csv"), os.path.join("imports", assign_name+".zip")
124 |
125 | moodle_gradesheet(notebook_name, assign_name, gradesheet_csv, archive_fname)
126 |
--------------------------------------------------------------------------------
/Scripts/moodle_nbgrader/update_gradesheet.py:
--------------------------------------------------------------------------------
1 | import nbgrader, csv, codecs, sys, os, shutil
2 | from nbgrader.apps import NbGraderAPI
3 | import zipfile
4 | verbose = False
5 | def zip(out, root):
6 | shutil.make_archive(out, 'zip', root)
7 |
8 | def moodle_gradesheet(assignment, with_feedback=True):
9 |
10 | api = NbGraderAPI()
11 | gradebook = api.gradebook
12 | csvfile = os.path.join("imports", assignment+".csv")
13 | with open(csvfile, newline='', encoding='utf-8-sig') as f:
14 | reader = csv.DictReader(f)
15 |
16 | fname = os.path.join("exports", assignment+".csv")
17 |
18 | if with_feedback:
19 | archive = zipfile.ZipFile(os.path.join("exports", "feedback_"+assignment+".zip"), 'w', zipfile.ZIP_DEFLATED)
20 |
21 |
22 | with open(fname, 'w', encoding='utf-8', newline='') as out:
23 | writer = csv.DictWriter(out, reader.fieldnames)
24 | writer.writeheader()
25 | for line in reader:
26 | email, ident, fullname, status, grade, max_grade = line["Registration number"], line['Identifier'], line['Full name'], line['Status'], line['Grade'], line['Maximum Grade']
27 | unique_id = email[0:7]
28 | try:
29 | submission = gradebook.find_submission(assignment, unique_id)
30 | except:
31 | if "Submitted" in status:
32 | print("WARNING: No submission for {id} in assignment {assign}".format(id=unique_id ,assign=assignment))
33 | else:
34 | if verbose:
35 | print("\tNo submission for {id} in assignment {assign}, as expected".format(id=unique_id, assign=assignment))
36 | else:
37 | if verbose:
38 | print("\tProcessing submission for {id} in assignment {assign}".format(id=unique_id, assign=assignment))
39 |
40 |
41 | fbk_path = os.path.join("feedback", unique_id, assignment)
42 |
43 | try:
44 |
45 | files = [os.path.join(fbk_path, f) for f in os.listdir(fbk_path) if f.endswith('.html')]
46 |
47 | assign_id = ident[12:]
48 | # remove asterisks
49 | name = 'blank'
50 |
51 | # create the path to the feedback file
52 | fbk_full_path = "{fullname}_{assign_id}_assignsubmission_file_".format(fullname=name,
53 | assign_id=assign_id)
54 | for f in files:
55 | archive.write(f, arcname=os.path.join(fbk_full_path, os.path.basename(f)))
56 |
57 | except FileNotFoundError:
58 | print("HTML feedback file for {fullname} {id} {assign} is missing".format(id=unique_id,
59 | fullname=fullname, assign=assignment))
60 | # no feedback to generate
61 |
62 | line['Grade'] = submission.score
63 |
64 | # warn about dubious scores
65 | if line['Grade']<=0 or line['Grade']>submission.max_score:
66 | print("Warning: {matric} {name} has a score of {grade}".format(matric=unique_id,
67 | name=fullname, grade=line['Grade']))
68 |
69 | # correct the maximum grade
70 | line['Maximum Grade'] = submission.max_score
71 | writer.writerow(line)
72 |
73 | print("Wrote to {0}".format(fname))
74 |
75 | # tidy up the feedback file
76 | if with_feedback:
77 | archive.close()
78 |
79 |
80 | if __name__=="__main__":
81 | if len(sys.argv)!=2:
82 | print("""
83 | Usage:
84 |
85 | update_gradesheet.py
86 |
87 | Updates a CSV file gradesheet (which must have be downloaded from
88 | Moodle with "offline gradesheets" enabled in the assignment settings) with
89 | the results from grading the assignment .
90 |
91 | The input will be imports/.csv
92 | The output will be in exports/.csv
93 |
94 | Feedback will be zipped up into the file exports/_feedback.zip and this
95 | can be uploaded to Moodle if "Feedback files" is enabled. This uploads all student
96 | feedback in one go.
97 |
98 | """)
99 | exit(-1)
100 |
101 | assignment= sys.argv[1]
102 | print("Updating gradesheet for {0}...".format(assignment))
103 | moodle_gradesheet(assignment)
104 |
--------------------------------------------------------------------------------
/Scripts/snippets/semweb_dependencies.py:
--------------------------------------------------------------------------------
1 | %%capture
2 | # The line above suppresses output. If there are errors, remove it.
3 | # Execute this cell once to install and update all needed packages. Could take a while, please wait until this process is finished before continuing.
4 | # When the cell is finished, the [*] to the left of the cell turns into a number, e.g. [1].
5 | import sys
6 | !{sys.executable} -m pip install git+https://github.com/SemWebNotebooks/Jupyter-RDFify.git -U
7 | # The line below installs the python graphviz interface together with the grahpviz binaries.
8 | # If you do not use anaconda, you need to install graphviz by hand and add it to your path as well as install the graphviz
9 | # interface with pip (pip install graphviz)
10 | !conda install --override-channels --yes --prefix {sys.prefix} -c conda-forge python-graphviz
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | # To install use the following command: conda env create --file environment.yml
2 | # This will install Jupyter Notebook, Graphviz and Jupyter-RDFify in the environment jupyter-rdfify
3 | # Then to activate the environment: conda activate jupyter-rdfify
4 | # Then to start the notebook server: jupyter notebook
5 | name: jupyter-rdfify
6 | dependencies:
7 | - conda-forge::notebook
8 | - conda-forge::graphviz
9 | - pip
10 | - pip:
11 | - jupyter-rdfify
--------------------------------------------------------------------------------