SQL View Constraints

SQL View Constraints are relationships that you can define between SQL Views in the mappings, which, along with the Keys in the views, will be used by Mastro at run-time to optimize its query answering process. Monolith allows you to create two different kinds of view constraints: Inclusions and Denials.
Once created, SQL View Constraints are shown both in the SQL View Constraints tab of the Mappings module, and in the SQL Views tab, under the SQL Views which are involved in them.

Inclusion Constraints

Inclusion Constraints determine inclusion relationships between pairs of (columns of) SQL Views. So for each Inclusion Constraint, you will have an Included SQL View, and an Including SQL View. The number of columns that are involved in the inclusion, for each of the two views, must be the same.

Let’s see an example. Go to the SQL Views tab, and pick the unedited_book_view from the SQL View tree. In the Constraints section of the view, you will find the following inclusion (with the Included view on the left of the arrow and the Including one on the right):

unedited_book(code) -> book(bk_code)

This inclusion means that each value in the code column of the unedited_book view will also be a value in the bk_code column of the book view.
It is also possible to define inclusions which involve more than one column of the included and including view.

Like we did with Keys, let’s see the role that Inclusions play in Mastro query answering process through a couple of examples.

Example 1. Consider the following SPARQL query, which asks for every man that has a name, but without returning the name:

SELECT ?x
WHERE {
  ?x a :Man.
  ?x :name ?y
}

Now, assuming that the ontology doesn’t contain axioms that involve :Man or :name, the Mapping Rewriting of the query, assuming the SQL Views man_view(x) and name_view(x,y), would be the following:

{x | man_view(x), name_view(x,y)}

However, if we define the inclusion man_view(x) -> name_view(x), then the above rewriting will be simplified like this: {x | man_view(x)}.
This rewriting will then in the SQL Rewriting step become the following SQL Query (assuming this is the SQL code of the view):

SELECT MV.ID
FROM (SELECT ID
      FROM TABLE_P
      WHERE SEX = 'M') as MV 

which can be further simplified into

    SELECT ID
    FROM TABLE_P
    WHERE SEX = 'M'

Example 2. Consider the following SPARQL query, which asks for every person:

SELECT ?x
WHERE {?x a :Person.}

and let’s assume that the ontology contains the following axioms:

SubClassOf(:Man :Person)
SubClassOf(:Woman :Person)
SubClassOf(:Person ObjectSomeValuesFrom(:name owl:Thing))

So, every man is a person, every woman is a person, and every person has a name.
According to the above ontology, the SPARQL query is rewritten (in the Ontology Rewriting step) into this query (we’ll use the compact logic notation for brevity):

{x | :Person(x)} U {x | :name(x,y)} U {x | :Man(x)} U {x | :Woman(x)}

So, a union of four queries. The Mapping Rewriting step will produce something like

{x | name_view(x,y)} U {x | man_view(x,y)} U {x | woman_view(x)}

However, if we define the inclusions

man_view(x) -> name_view(x)
woman_view(x) -> name_view(x)

then the above query is simplified into

{x | name_view(x,y)}}

which will then be transformed into an SQL in the SQL Rewriting step according to the definition of the view name_view.

Denial Constraints

Denial Constraints are a general form of logical disjunctions, which basically define that joining two (or more) SQL Views will produce an empty result set. In logic, we can write this as

man_view(x), woman_view(x) -> FALSE

Intuitively, knowing these Denial Constraints lets Mastro discard Mapping Rewritings which will surely produce no answers in the query evaluation step. Let try an example.

Example. Consider the following SPARQL query, which asks for anything that is part of a university.

SELECT ?x
WHERE {
  ?x :partOf ?y.
  ?y a :University.
}

and assume that you have defined the following mappings (in compact notation for brevity):

View1(Dipartment_ID, UniversityID) -> :partOf(Dipartment_ID, UniversityID)
View2(Branch_ID, Bank_ID) -> :partOf(Branch_ID, Bank_ID)
View1(Dipartment_ID, UniversityID) -> :University/UniversityID)

and also this Denial Constraint:

View1(x,y),View2(x,y') -> FALSE

Assuming no new rewritings are produced in the Ontology Rewriting step, the Mapping Rewriting step will produce the following rewriting:

{x | View1(x,y), View1(x',y)} U {x | View1(x,y), View2(x,y')}

However, the Denial Constraint tells us that the second query in the above union will produce an empty results set, and so it can be safely eliminated prior to evaluation.

Creating SQL View Constraints

To create a new Inclusion Constraint between SQL Views, move to the Inclusions Page (SQL View Constraints -> Inclusions), and press the “Add Inclusion Constraint” button near the search bar. The Editing Drawer will slide out, and you can select the Included View on the left hand side column, and the Including View on the right hand side column.
For example, select edition_view as the Included View, and book_view as the Including View.

Now, from the drop-down menus, pick the parameters for each view that will be considered in the Inclusion Constraint. Select bk_id from edition_view, and code from book_view. Then, press the Save button.
The new Inclusion Constraint will have been added to the list.

Denial Constraints in Monolith can be simply expressed as SQL Queries over the SQL Views of the mapping. These queries are interpreted by Mastro as being extensionally empty. Therefore, the SELECT statement of the query can always be simply defined as *.
To create a new Denial Constraint, move to the Denials Page (SQL View Constraints -> Denials), and press the “Add denial” button from the Denials tree on the left hand side. Then, simply provide a name for the Denial, and its SQL Code. Remember that, just like for Ontology Mappings, in the SQL Code of the Denial, when defining joins between different tables, Monolith requires to use explicit joins instead of implicit joins.
For example:

SELECT * 
FROM editions e 
  join unedited_book u 
      on e.bk_id = u.code  

Previous Next