BookTutorial - ConstantB/ontop-spatial GitHub Wiki

Table of Contents

Book Publication

In this tutorial we are going to explore a more applicable exercise. We recommend to take a look at the HelloWorld tutorial before going into this tutorial. It focuses on Quest in Virtual RDF Graph mode (or previously known as Virtual ABox mode) which means doing queries over the database through the ontology on-the-fly (without requiring any data import action).

The tutorial is organized by use-cases that have a specific objective in each scenario. Try to follow each of the steps and the instructions in your local machine.

Prerequisite

The database

The "books" database consists of 7 tables with some relations between them. The structure is shown as follows:

Follow the instructions here to have the database installed in your local machine. You may also import the data to other database system as you desired using this SQL script.

The Ontology

We will use an existing ontology (download exampleBooks.owl). It is a simple ontology which consists of 12 classes, 3 object properties and 6 data properties. The ontology specifies a couple of hierarchies, domain and range axioms, mandatory participation axioms (e.g., name min 1 Literal), and other OWL 2 QL axioms.

Connect to the Data Source

Connecting a data source using -ontopPro- works as follows:

  1. Select the "OBDA Model" tab.
  2. Go to "Datasource Manager" sub-tab and click on the "Create New..." button.
  3. Type "BookPublication" as the ID for the data source (any name will do).
  4. Fill in the JDBC connection parameters according to our tutorial database configuration:
    • Connection URL: jdbc:h2:tcp://localhost/books;DATABASE_TO_UPPER=FALSE
    • Database Username: sa
    • Database Password: (blank)
    • Driver class: org.h2.Driver
TIP: To become familiar with JDBC Drivers or JDBC connections please read the information we have in the JDBC page.

Use Cases

The table below lists the tutorial cases. Each case assumes that you have completed the previous cases.

Case1 Start here. Simple mapping to handle basic queries (i.e., a simple data retrieval from a table without any conditions).
Case2 Mappings for different levels of a hierarchy using SQL with conditions. Hierarchical inference.
Case3 Demonstrate how to create mappings for data properties and how to include these data properties in SPARQL queries. Demonstrates more advanced ABox queries using SPARQL.

We are going to approach each case in three steps:

  • The first step looks for any relevant Classes or Object Properties or Data Properties in the ontology, and any relevant Tables in the database that match the requirement.
  • The second step constructs the OBDA model that maps the data in the database and the classes and properties in the ontology.
  • Last, the third step tests the OBDA model by executing a query using a reasoner. The query is written using SPARQL.

Case 1

In this example case we map an ontology classes and properties to database tables. The exercise shows:

  • Basic mapping creation
  • Basic ABox queries using SPARQL
We define the requirements for this example case as follows:
  • RE-001: Query for all the author names.
  • RE-002: Query for all the book titles.
  • RE-003: Query for all the editor names.
Step 1: Analysis of sources and targets From the ontology, we will need to map the following entities:
  • Classes , i.e., Author, Book and Editor.
  • Data properties, i.e., name and title.
Analysing our database we find that the following tables can be used to create mappings for these classes and properties: i.e., tb_affiliated_writers, tb_books and tb_editor.

We can see that there is a one to one correspondance of the entities stored in the tables, and the classes we want to map. Likewise, the columns wr_name, ed_name and bk_title can be used for the data properties. To create the URI's for the book, editor and author entities we could use the primary keys of these tables or the titles and names of these. In this case we will use the primary keys.

Step 2: Creating mappings

Having analysed the tables, now we express this analysis as the following mappings:

Note : We present the mapping as [Source] --> [Target].

  • RE-001: Query for all the author names.
select wr_code,wr_name from <font color="#7E2217">tb_affiliated_writers</font> --> :author/{wr_code}/ a <font color="#E9AB17">:Author</font> ; <font color="#4AA02C">:name</font> {wr_name} .
  • RE-002: Query for all the book titles.
select bk_code,bk_title from <font color="#7E2217">tb_books</font> --> :book/{bk_code}/ a <font color="#E9AB17">:Book</font> ; <font color="#4AA02C">:title</font> {bk_title} .
  • RE-003: Query for all the editor names.
select ed_code,ed_name from <font color="#7E2217">tb_editor</font> --> :editor/{ed_code}/ a <font color="#E9AB17">:Editor</font> ; <font color="#4AA02C"> :name</font> {ed_name} .

To add these mappings open the "Mapping Manager" tab, select Books as the data source and then insert the mappings one by one, clicking on the "create new mapping" button.

Each of these mappings accomplishes three things at the same time, 1. they create URI's for individuals, 2. they state that this individual belongs to a class (is instance of a class) and 3. associate this individual with a value (the name or title). The URI for this individual is defined as a template that gets "filled" using the values that come from the columns in SQL query in the mapping.


Step 3: SPARQL queries

The last step is starting Quest and asking SPARQL queries to verify their answers. To do this first start Quest (Reasoner's menu, click on Reasoner > Quest 1.7 and then "Start reasoner"). Then switch to the Query tab and execute the following SPARQL queries:

  • RE-001: Query for all the author names (22 tuples)
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :Author. ?x :name ?y} 
  • RE-002: Query for all the book titles (24 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :Book. ?x :title ?y} 
  • RE-003: Query for all the editor names (11 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :Editor. ?x :name ?y}

NOTE: The value for ?x in these queries is always a URI. This URI was constructed in the way we specified in the "target" of each of the mappings we created in the previous step. In this case we used the Primary Key to create these URIs, however, you are free to use other values. To learn more about URI templates and -ontop- mappings see our documentation on mappings

Case 2

In this example case, you we add mappings for the sub-classes of a hierarchy using more constrained SQL queries.

We define the requirements for this example case as follows:

  • RE-004: Query for all the titles that all audio books.
  • RE-005: Query for all the names for all authors that are an emerging writer.
  • RE-006: Query for all the dates of publication and edition numbers of books that are special editions.
Step 1: Analysing the sources and targets From the ontology we want to map the following entities:
  • Classes , i.e., EmergingWriter, AudioBook and SpecialEdition. Notice that these are sub-classes of other classes (see the ontology schema).
  • Data properties, i.e., name, title, dateOfPublication and editionNumber. Notice that some of these properties are shared between objects belonging to different classes. You will see that we will map them differently, depending on the kind of object attached to the values retrieved from the source (i.e., is it the name of a book, or the name of an author?).
Looking at the database we find that the following tables have data for the previous entities: tb_on_prob_wr, tb_books and tb_edition. In one case, tb_books, we have used the rows in this table to already create Book individuals. However, in this new mappings we will refine our SQL query to identify a particular kind of book in this rows, AudioBooks. We know that a row in this table identifies an AudioBook based on the value of the bk_type column.

Step 2: Creating mappings

Go to the "Mapping Manager" tab, select Books as the data source and then insert these following mappings.

  • RE-004: Present all the book titles that are a audio book.
select bk_code from <font color="#7E2217">tb_books</font> where bk_type='A' --> :book/{bk_code}/ a <font color="#E9AB17">:AudioBook</font> .
TIP: We exclude the title property from this mapping because all the URI's (individuals) created from the rows of this table already have been associated to a title. This is so because of the previous mappings we created in Case 1. We could still add name to the target of the mapping, however this would be redundant and could introduce inefficiency and is better to avoid it and create mappings with no redundancy.
  • RE-005: Present all the author names that are an emerging writer.
select wr_code,wr_name from <font color="#7E2217">tb_on_prob_wr</font> --> :author/{wr_code}/ a <font color="#E9AB17">:EmergingWriter</font> ; <font color="#4AA02C">:name</font> {wr_name} .
  • Note :
The EmergingWriter is a sub-class of Author. However, both's classes do NOT share the same data source (i.e., one uses the table tb_on_prob_wr another the table tb_affiliated_writers). Thus, it is necessary to add new mappings to make sure that emerging writers also have a value for name.
  • RE-006: Present all the date of publication of a special edition.
select ed_code,pub_date,n_edt from <font color="#7E2217">tb_edition</font> --> :edition/{ed_code}/ a <font color="#E9AB17">:Edition</font> ; <font color="#4AA02C">:dateOfPublication</font> {pub_date} ; <font color="#4AA02C">:editionNumber</font> {n_edt} .
select ed_code,pub_date,n_edt from <font color="#7E2217">tb_edition</font> where ed_type='S' --> :edition/{ed_code}/ a <font color="#E9AB17">:SpecialEdition</font> .

Step 3: SPARQL queries

Open the "OBDA Query" tab and use the following SPARQL queries to get the answers to our requirements.

TIP: The new mappings are treated as axioms by Protege, and hence, for the new mappings to take effect you need to synchronize them with the reasoner. To do this, click on the reasoners menu item "synchronize reasoner".
  • RE-004: Query for all the books that are audio book (5 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :AudioBook. ?x :title ?y}
  • RE-005: Query for all the author names that are an emerging writer (3 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :EmergingWriter. ?x :name ?y}
  • RE-006: Query for all the date of publication of a special edition (7 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y ?z where {?x rdf:type :SpecialEdition. ?x :dateOfPublication ?y. ?x :editionNumber ?z}

Reasoning: Note that you can now exploit the hierarchies of your ontology. For example, if you query for all writers, Quest will correctly use the data from tb_on_prob_wr AND tb_affiliated_writers to answer your query. The query is:

PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?x ?y where {?x rdf:type :Writer. ?x :name ?y}

Case 3

The exercise demonstrates:

  • How to map object properties.
  • More advanced SPARQL queries and conditions in the query.
We define the requirements for this example case as follows:
  • RE-007: Query for all the book titles written by a specific author.
  • RE-008: Query for the complete information about a book, including its author, genre, publication date and edition number.
Step 1: Analysis of sources and targets
  • From the ontology we need to create mappings for:
    • Object properties, i.e., writtenBy and hasEdition.
    • Data properties, i.e., name, title, genre, dateOfPublication and editionNumber
  • From the database schema we have the corresponding tables, i.e., tb_affiliated_writers, tb_authors, tb_books, tb_bk_gen and tb_edition.

Step 2: Creating the mappings

Go to the "Mapping Manager" tab, select Books as the data source and then insert these following mappings.

  • RE-007: Present all the book titles written by a specific author.
select bk_code,wr_id from <font color="#7E2217">tb_authors</font> --> :book/{bk_code}/ <font color="#1569C7">:writtenBy</font> :author/{wr_id}/ .
  • Note :
Mapping a relation requires that we create two URI's, one for each individual. To construct the URI's we use URI templates and use the values for the primary key or foreign key as the parameters for these templates. The writtenBy property uses two foreign keys in tb_authors table that relates books and writers with respect to authorship. It is important to use the same URI template that we used in the mappings for the classes Book and Author, otherwise we would be introducing new individuals to our model instead of referencing to existing ones. See URI templates for more information about URI construction.
  • RE-008: Present the complete information about a book, including its author, genre, publication date and edition number.
select ed_code,bk_id from tb_edition --> :book/{bk_id}/ <font color="#1569C7">:hasEdition</font> :edition/{ed_code}/ .
select id_bk,gen_name from tb_bk_gen --> :book/{id_bk}/ <font color="#4AA02C">:genre</font> {gen_name} .
  • Note :
The hasEdition property uses a foreign key and a primary key in tb_edition table that relates books and editions with respect to the book publication. Additionally, we add one more data property for the book (i.e., genre) to meet the requirement.

Step 3: SPARQL Queries

Go to the "OBDA Query" tab and use these individual ABox queries to fetch the result from the database. Note : Don't forget to synchronise the reasoner.

  • RE-007: Present all the book titles written by a specific author (2 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
select distinct ?title where {?x rdf:type :Book. ?x :title ?title. ?x :writtenBy ?y. ?y rdf:type :Author. ?y :name "L.C. Higgs"^^xsd:string}
  • Notes :
1) We put "L.C. Higgs" as the author. 2) You might have to take ^^xsd:string out of the query to get some result.
  • RE-008: Present the complete information about a book, including its author, genre, publication date and edition number (31 tuples).
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?title ?author ?genre ?edition where {
  ?x rdf:type :Book. ?x :title ?title. ?x :genre ?genre. ?x :writtenBy ?y. ?x :hasEdition ?z. 
  ?y rdf:type :Author. ?y :name ?author. 
  ?z rdf:type :Edition. ?z :editionNumber ?edition}
PREFIX : <http://meraka/moss/exampleBooks.owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?title ?author ?genre ?edition where {
  ?x a :Book; :title ?title; :genre ?genre; :writtenBy ?y; :hasEdition ?z. 
  ?y a :Author; :name ?author. 
  ?z a :Edition; :editionNumber ?edition}
  • Note :
Both queries are equivalent. However, we trimmed the latter query.

Resources

  1. exampleBooks.owl. The OWL ontology file.
  2. exampleBooks.obda. The OBDA file.
  3. exampleBooks.q. The Q file.
  4. books.sql. The data source.
⚠️ **GitHub.com Fallback** ⚠️