{{announcement.body}}
{{announcement.title}}

Comparing Graql to SQL — Part 2/2

DZone 's Guide to

Comparing Graql to SQL — Part 2/2

In this article, see part two of a comparison of Graql and SQL and learn how to read/write data and how we should model at a higher-level in Graql.

· Database Zone ·
Free Resource

This is part two of Comparing Graql to SQL. In the first part, we looked at the origin of the relational model and how to go about modeling in both Graql and SQL. In this part, we look at how to read/write data, and how we should model at a higher-level in Graql leveraging the Hypergraph and Automated Reasoning. If you haven’t read part 1, follow this link.

Inserting Data

Let’s look at how we write and read data using relational operators. First, using the Northwind schema, let’s insert the following data: a new product with name Chocolate, product id 12, quantity per unit 421 and category name Confections.

In SQL, we do two queries. First, we fetch the ID of Confections and then we insert the new row.

SQL
 




x


 
1
SELECT category.categoryID
2
FROM category
3
WHERE category.CategoryName = "Confections";
4
INSERT INTO products
5
VALUES (12, "Chocolate", 42, 421)



In Graql we do something different. We first match for the Confections category, assign the result to the variable $c, and then insert the new data.

Java
 




xxxxxxxxxx
1


1
match 
2
$c isa category, 
3
  has name "Confections"; 
4
insert 
5
$p isa product,
6
  has product-id 12, 
7
  has product-name "Chocolate", 
8
  has quantity-per-unit 421;



Reading Data

The basic operational construct in SQL is the SELECT - WHERE - FROM expression, which is used to derive new tables from existing ones.

SQL
 




xxxxxxxxxx
1


 
1
SELECT column1, column2, …
2
FROM table_name
3
WHERE condition;



The equivalent expression in Graql is the match-get expression.

Java
 




xxxxxxxxxx
1


 
1
match 
2
$a isa thing,
3
  has attribute $v;
4
get $a, $v;



Let’s look at some of the most commonly used operators in SQL and how these look in Graql. In doing so, we’re going to look at how to think about a query conceptually, instead of looking at the actual code. In this way, the difference between a Graql and a SQL query is that in Graql we think of queries at a conceptual level; the same way we semantically think about a question, rather than imposing a tabular structure over it.

In the figures below, on the left side, the tabular representation of the query in SQL is shown, and on the right the conceptual representation of the query in Graql (squares are entities, diamonds are relations and circles are attributes).

Projection

This SQL operator returns a table that contains all the rows that remain after specific columns have been removed. In Graql, we ask for an entity with specific attribute values.

An example is:

Return all product IDs and their unit prices.

Table projection (left) and the equivalent operation in Graql (right).

Restrict

This SQL operator gives us a table with rows from a specified table to a specific condition. In Graql, we ask for an entity and its attributes filtered by an attribute with specific values.

Return product IDs and product names, for products with a unit price higher than 12.5.

Table restriction (left) and the equivalent operation in Graql (right).

Union

This SQL operator returns the rows of the tables that appear in either or both of the two specified tables. In Graql, we ask for entities and their attributes that are connected to one or two other entities through a relation.

Get all the different cities in which suppliers and customers are located.

Table union (left) and the equivalent operation in Graql (right).

Intersect

This SQL operator returns a table with all rows that appear in both of two specified tables. In Graql, we ask for an entity that is connected to two specific entities through a relation.

Get all the cities in which suppliers and customers are simultaneously located.

Table intersection (left) and the equivalent operation in Graql (right).

Join

The most famous SQL operator, a join returns a table containing all possible rows that are a combination of two rows, one from each of two specified tables, such that two rows contributing to any given result row have common values for the common attributes of the two tables. In Graql, we ask for the entities and their attributes that are connected through a specific relation. This means that we don’t need any join tables at all, not for 1–1 relations, 1-many relations, or many-many relations. The concept is no longer needed in Grakn.

Get all the different cities in which suppliers and customers are located.

Table join (left) and the equivalent operation in Graql (right).

Modeling at a Higher-Level in Graql: Hypergraph and Automated Reasoning

Compared to SQL, Graql allows us to model at a higher level of abstraction. This means that when we think about queries, we shouldn’t actually think in terms of relational operators, as we’ve just done in the previous section. Instead, we should rethink our model and leverage Graql’s expressivity. So, let’s revisit the Northwind dataset and think about how we can model it differently. In particular, let’s look at how we make use of Grakn’s hypergraph and reasoning capabilities.

Modeling in Graql

If we take the suppliers, products, employees, orders and customers tables from the Northwind dataset, we can model this in Graql by creating the following entities:

  1. Product: We map this entity directly to the products table (using the singular term instead).
  2. Order: This maps directly to the orders table.
  3. Employee: This also maps directly to the employees table.
  4. Company: As both the suppliers and customers table refer to companies, we decide to model them as one entity type. We can define a company as a supplier or a customer with roles (see below).

We then create the following relations and corresponding roles:

  1. Sale: We can model this relation as ternary (learn more about hypergraphs), as a sale occurs between an Order (playing the placed-order role), Company (playing the customer role) and an Employee (playing the role of seller).
  2. Stocking: This relation relates to a Product (playing the role of stock) which is being stocked by another Company, which plays the role of supplier.
  3. Containing: We define this relation between the entity Order (playing the role of containing-order) and Product (role of containing-product), because an order can contain multiple products. We also add two attributes to this relation: quantity and unit-price.

This is what we’ve just modeled:

The model of the Northwind dataset in Graql.


Let’s see how this looks in Graql:

Java
 




xxxxxxxxxx
1
34


1
define 
2
 
          
3
employee sub entity, 
4
  plays seller; 
5
 
          
6
company sub entity, 
7
  plays supplier,
8
  plays customer; 
9
 
          
10
order sub entity, 
11
  plays placed-order,
12
  plays containing-order; 
13
 
          
14
product sub entity, 
15
  plays containing-product,
16
  plays stock;
17
 
          
18
sale sub relation, 
19
  relates placed-order,
20
  relates seller, 
21
  relates customer;
22
 
          
23
containing sub relation, 
24
  has quantity,
25
  has unit-price,
26
  relates containing-product, 
27
  relates containing-order;
28
 
          
29
stocking sub relation, 
30
  relates stock, 
31
  relates supplier;
32
 
          
33
quantity sub attribute, datatype double; 
34
unit-price sub attribute, datatype double;



Traversal Queries

Writing a traversal query in SQL means we leverage the JOIN operator. Below is a comparison between SQL and Graql for the following question:

Return all employee IDs who sold to a customer based in London, and has customer demographic "x"

SQL
 




xxxxxxxxxx
1
12


1
SELECT Employees.EmployeeID
2
FROM Employees 
3
  INNER JOIN Orders ON 
4
    Employees.EmployeeID = Orders.EmployeeID
5
  INNER JOIN Customers ON 
6
    Orders.CustomerID = Customers.CustomerID 
7
    AND Customers.City = 'London'
8
  INNER JOIN CustomerCustomerDemo ON
9
    Customers.CustomerID = CustomerCustomerDemo.CustomerID
10
  INNER JOIN CustomerDemographic ON
11
    CustomerCustomerDemo.CustomerTypeId = CustomerDemographic.CustomerTypeId 
12
    AND CustomerCustomerDemo.CustomerDesc = 'x'



Java
 




xxxxxxxxxx
1


 
1
match 
2
$s isa employee, has employee-id $eid; 
3
$c isa company, has city "London"; 
4
$r1 ($s, $c) isa sale; 
5
$cd isa customer-demographic, has customer-description "x"; 
6
$r2 ($c, $cd); 
7
get $eid;


Type-Based Reasoning

Unlike in SQL, in Graql we have the capability to increase the expressivity of our model by creating a type hierarchy. For example, we can extend the Northwind dataset by adding non-profits, banks and pharmaceutical companies. Conceptually, this looks as follows:

Type-hierarchy example.

And in Graql we define it as follows:

Java
 




xxxxxxxxxx
1


 
1
define 
2
organisation sub entity; 
3
  
4
for-profit sub organisation; 
5
non-profit sub organisation; 
6
 
          
7
bank sub for-profit; 
8
pharmaceutical sub for-profit;



Rule-Based Reasoning

With Graql, we can also create rules (learn more here) to abstract and modularise our business logic. SQL does not support rules. For example, if we know that location x is contained in y, which in turn is contained in z, we can create a rule that recursively infers that x is also contained in z. Writing this in Graql looks like this:

Java
 




xxxxxxxxxx
1


1
transitive-location sub rule, 
2
when { 
3
  (located: $x, locating: $y) isa locates; 
4
  (located: $y, locating: $z) isa locates; 
5
}, then { 
6
  (located: $x, locating: $z) isa locates; 
7
};



If we look at our Northwind dataset, we can see a transitivity exists between the Employees, Territories and Region tables which means we can leverage the rule above in Graql. To illustrate this point, let’s look at this question:

Return all the employee IDs who are in a region with region-description "x".

In SQL, this is written as follows:

SQL
 




xxxxxxxxxx
1


1
SELECT Employee.EmployeeID 
2
FROM Employee 
3
  INNER JOIN EmployeeTerritories AS Et ON
4
    Employee.EmployeeID = Et.EmployeeID 
5
  INNER JOIN Territories AS Te ON
6
    Te.TerritoryID = Et.TerritoryID 
7
  INNER JOIN Region AS Re ON
8
    Re.RegionID = Te.RegionID 
9
    AND Re.RegionDescription = 'x'



Having defined the transitive-location rule in Graql, we can now directly relate the employee to the region (abstracting away the territory to region connection avoiding us having to make multiple joins):

Java
 




xxxxxxxxxx
1


 
1
match 
2
$e isa employee, has employee-id $eid; 
3
$r isa region, has region-description "x"; 
4
$r1 (located: $e, locating: $r) isa locates; 
5
get $eid;



If we also incorporate the organization type-hierarchy shown earlier, we can abstract away even more logic to Grakn. Let’s use this question as an example:

Return the IDs for customers that are companies and charities, that employees have sold to, and who are in a region with region-description "x".

In SQL, we write this query like this:

SQL
 




xxxxxxxxxx
1
27


 
1
SELECT Companies.OrgID 
2
FROM Companies 
3
  INNER JOIN Orders ON 
4
    Companies.OrgId = Orders.OrgId
5
  INNER JOIN Employees ON 
6
    Orders.OrgId = Employees.OrgId
7
  INNER JOIN EmployeeTerritories AS Et ON
8
    Employees.EmployeeID = Et.EmployeeID 
9
  INNER JOIN Territories AS Te ON
10
    Te.TerritoryID = Et.TerritoryID 
11
  INNER JOIN Region AS Re ON
12
    Re.RegionID = Te.RegionID 
13
    AND Re.RegionDescription = 'x'
14
UNION 
15
SELECT Charities.OrgID 
16
FROM Charities
17
  INNER JOIN Orders ON 
18
    Charities.OrgId = Orders.OrgId
19
  INNER JOIN Employees ON 
20
    Orders.OrgId = Employees.OrgId
21
  INNER JOIN EmployeeTerritories AS Et ON
22
    Employees.EmployeeID = Et.EmployeeID 
23
  INNER JOIN Territories AS Te ON
24
    Te.TerritoryID = Et.TerritoryID 
25
  INNER JOIN Region AS Re ON
26
    Re.RegionID = Te.RegionID 
27
    AND Re.RegionDescription = 'x'



In Graql, we simply write:

Java
 




xxxxxxxxxx
1


1
match 
2
$c isa organisation, has org-id $ci; # Organisation infers sub entities companies and charities
3
$e isa employee; 
4
$r isa region, has region-description "x"; 
5
$r1 (located: $e, locating: $r) isa locates; 
6
$r2 ($c, $e) isa sale; 
7
get $ci;



Conclusion

In conclusion, we’ve seen how:

  • Graql provides a higher-level abstraction for working with data. Graql makes it easier to model and query for complex data.
  • Graql lets us create conceptual models giving us the physical independence of data. By implementing a concept level schema, Graql abstracts away the logical model. This means we no longer need to normalize our data.
  • Grakn’s reasoning engine simplifies our queries. By using an automated reasoner, Grakn pushes down lower-level operations and enables us to work at a higher level of abstraction.

Grakn’s reasoning engine allows us to abstract away logic that otherwise happens in either our query or application layer. Pushing this logic down into Grakn allows us to write simpler queries at a higher-level of expressivity.

There is much more to Graql than what we’ve tried to show here. Hopefully this comparison has at least given the high-level similarities and differences between both languages.

Topics:
database ,graql ,sql ,sql comparison ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}