Lesson 7.4: Value comparisons
TypeQL provides several operators for comparing the values of attributes and literals in patterns.
- Equality operators
-
==
,!=
- Ordering operators
-
>
,>=
,<
,<=
- String matching operators
-
contains
,like
We have already seen a few examples of them in previous lessons.
Equality operators
The equality operators are valid for comparing values of all value types. We can compare the values of attributes either to those of literals or to those of each other. In the following Fetch query, we retrieve a list of books that were published in a city other than New York.
match
$book isa book;
($book, $publication) isa publishing;
($publication, $city) isa locating;
$city isa city, has name != "New York City";
fetch
$book: isbn-13;
In this next query, we retrieve pairs of books that were published in the same year.
match
$book-1 isa book;
$book-2 isa book;
($book-1, $publication-1) isa publishing;
($book-2, $publication-2) isa publishing;
$publication-1 isa publication, has year $year-1;
$publication-2 isa publication, has year $year-2;
not { $book-1 is $book-2; };
$year-1 == $year-2;
fetch
$book-1: isbn-13;
$book-2: isbn-13;
Write a Fetch query to retrieve the IDs of users that are based outside the US. The entity representing the US has the name "United States".
You may find it useful to refer to the bookstore’s schema.
Schema
define
book sub entity,
abstract,
owns isbn-13 @key,
owns isbn-10 @unique,
owns title,
owns page-count,
owns genre,
owns price,
plays contribution:work,
plays publishing:published,
plays promotion-inclusion:item,
plays order-line:item,
plays rating:rated,
plays recommendation:recommended;
hardback sub book,
owns stock;
paperback sub book,
owns stock;
ebook sub book;
contributor sub entity,
owns name,
plays contribution:contributor,
plays authoring:author,
plays editing:editor,
plays illustrating:illustrator;
company sub entity,
abstract,
owns name;
publisher sub company,
plays publishing:publisher;
courier sub company,
plays delivery:deliverer;
publication sub entity,
owns year,
plays publishing:publication,
plays locating:located;
user sub entity,
owns id @key,
owns name,
owns birth-date,
plays action-execution:executor,
plays locating:located,
plays recommendation:recipient;
order sub entity,
owns id @key,
owns status,
plays order-line:order,
plays action-execution:action,
plays delivery:delivered;
promotion sub entity,
owns code @key,
owns name,
owns start-timestamp,
owns end-timestamp,
plays promotion-inclusion:promotion;
review sub entity,
owns id @key,
owns score,
owns verified,
plays rating:review,
plays action-execution:action;
login sub entity,
owns success,
plays action-execution:action;
address sub entity,
owns street,
plays delivery:destination,
plays locating:located;
place sub entity,
abstract,
owns name,
plays locating:located,
plays locating:location;
city sub place;
state sub place;
country sub place;
contribution sub relation,
relates contributor,
relates work;
authoring sub contribution,
relates author as contributor;
editing sub contribution,
relates editor as contributor;
illustrating sub contribution,
relates illustrator as contributor;
publishing sub relation,
relates publisher,
relates published,
relates publication;
promotion-inclusion sub relation,
relates promotion,
relates item,
owns discount;
order-line sub relation,
relates order,
relates item,
owns quantity,
owns price;
rating sub relation,
relates review,
relates rated;
action-execution sub relation,
relates action,
relates executor,
owns timestamp;
delivery sub relation,
relates deliverer,
relates delivered,
relates destination;
locating sub relation,
relates located,
relates location;
recommendation sub relation,
relates recommended,
relates recipient;
isbn sub attribute, abstract, value string;
isbn-13 sub isbn;
isbn-10 sub isbn;
title sub attribute, value string;
page-count sub attribute, value long;
genre sub attribute, value string;
stock sub attribute, value long;
price sub attribute, value double;
discount sub attribute, value double;
id sub attribute, value string;
code sub attribute, value string;
name sub attribute, value string;
birth-date sub attribute, value datetime;
street sub attribute, value string;
year sub attribute, value long;
quantity sub attribute, value long;
score sub attribute, value long;
verified sub attribute, value boolean;
timestamp sub attribute, value datetime;
start-timestamp sub attribute, value datetime;
end-timestamp sub attribute, value datetime;
status sub attribute, value string, regex "^(paid|dispatched|delivered|returned|canceled)$";
success sub attribute, value boolean;
rule review-verified-by-purchase:
when {
($review, $product) isa rating;
($order, $product) isa order-line;
($user, $review) isa action-execution, has timestamp $review-time;
($user, $order) isa action-execution, has timestamp $order-time;
$review-time > $order-time;
} then {
$review has verified true;
};
rule review-unverified:
when {
$review isa review;
not { $review has verified true; };
} then {
$review has verified false;
};
rule book-recommendation-by-genre:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
$liked-book has genre $shared-genre;
$new-book has genre $shared-genre;
not { {
$shared-genre == "fiction";
} or {
$shared-genre == "nonfiction";
}; };
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule book-recommendation-by-author:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
($liked-book, $shared-author) isa authoring;
($new-book, $shared-author) isa authoring;
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule order-line-total-retail-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
not {
($promotion, $item) isa promotion-inclusion;
$promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
$line has quantity $quantity;
?line-total = $quantity * $retail-price;
} then {
$line has price ?line-total;
};
rule order-line-total-discounted-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
($best-promotion, $item) isa promotion-inclusion, has discount $best-discount;
$best-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
not {
($other-promotion, $item) isa promotion-inclusion, has discount > $best-discount;
$other-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
?discounted-price = round(100 * $retail-price * (1 - $best-discount)) / 100;
$line has quantity $quantity;
?line-total = $quantity * ?discounted-price;
} then {
$line has price ?line-total;
};
rule transitive-location:
when {
(location: $parent-place, located: $child-place) isa locating;
(location: $child-place, located: $x) isa locating;
} then {
(location: $parent-place, located: $x) isa locating;
};
Hint
Enabling rule inference to leverage the rule transitive-location
will make this significantly easier.
Sample solution
match
$user isa user;
$country isa country, has name != "United States";
($user, $country) isa locating;
fetch
$user: id;
This query must be run with rule inference switched on.
Ordering operators
The ordering operators can be used to compare longs, doubles, and datetimes. We have already seen an example of their use in Lesson 7.3, where we retrieved a list of books that a user has eiter ordered or reviewed with a score of seven or higher.
match
$user isa user, has id "u0008";
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
fetch
$liked-book: isbn-13;
In this next query we retrieve a list of books that have a retail price under $15.
match
$book isa book, has price <= 15.00;
fetch
$book: isbn-13, title, price;
Write a Fetch query to retrieve the IDs of orders that were placed during the Holiday Sale 2023. The entity representing this sale has the code "HOL23".
You may find it useful to refer to the bookstore’s schema.
Schema
define
book sub entity,
abstract,
owns isbn-13 @key,
owns isbn-10 @unique,
owns title,
owns page-count,
owns genre,
owns price,
plays contribution:work,
plays publishing:published,
plays promotion-inclusion:item,
plays order-line:item,
plays rating:rated,
plays recommendation:recommended;
hardback sub book,
owns stock;
paperback sub book,
owns stock;
ebook sub book;
contributor sub entity,
owns name,
plays contribution:contributor,
plays authoring:author,
plays editing:editor,
plays illustrating:illustrator;
company sub entity,
abstract,
owns name;
publisher sub company,
plays publishing:publisher;
courier sub company,
plays delivery:deliverer;
publication sub entity,
owns year,
plays publishing:publication,
plays locating:located;
user sub entity,
owns id @key,
owns name,
owns birth-date,
plays action-execution:executor,
plays locating:located,
plays recommendation:recipient;
order sub entity,
owns id @key,
owns status,
plays order-line:order,
plays action-execution:action,
plays delivery:delivered;
promotion sub entity,
owns code @key,
owns name,
owns start-timestamp,
owns end-timestamp,
plays promotion-inclusion:promotion;
review sub entity,
owns id @key,
owns score,
owns verified,
plays rating:review,
plays action-execution:action;
login sub entity,
owns success,
plays action-execution:action;
address sub entity,
owns street,
plays delivery:destination,
plays locating:located;
place sub entity,
abstract,
owns name,
plays locating:located,
plays locating:location;
city sub place;
state sub place;
country sub place;
contribution sub relation,
relates contributor,
relates work;
authoring sub contribution,
relates author as contributor;
editing sub contribution,
relates editor as contributor;
illustrating sub contribution,
relates illustrator as contributor;
publishing sub relation,
relates publisher,
relates published,
relates publication;
promotion-inclusion sub relation,
relates promotion,
relates item,
owns discount;
order-line sub relation,
relates order,
relates item,
owns quantity,
owns price;
rating sub relation,
relates review,
relates rated;
action-execution sub relation,
relates action,
relates executor,
owns timestamp;
delivery sub relation,
relates deliverer,
relates delivered,
relates destination;
locating sub relation,
relates located,
relates location;
recommendation sub relation,
relates recommended,
relates recipient;
isbn sub attribute, abstract, value string;
isbn-13 sub isbn;
isbn-10 sub isbn;
title sub attribute, value string;
page-count sub attribute, value long;
genre sub attribute, value string;
stock sub attribute, value long;
price sub attribute, value double;
discount sub attribute, value double;
id sub attribute, value string;
code sub attribute, value string;
name sub attribute, value string;
birth-date sub attribute, value datetime;
street sub attribute, value string;
year sub attribute, value long;
quantity sub attribute, value long;
score sub attribute, value long;
verified sub attribute, value boolean;
timestamp sub attribute, value datetime;
start-timestamp sub attribute, value datetime;
end-timestamp sub attribute, value datetime;
status sub attribute, value string, regex "^(paid|dispatched|delivered|returned|canceled)$";
success sub attribute, value boolean;
rule review-verified-by-purchase:
when {
($review, $product) isa rating;
($order, $product) isa order-line;
($user, $review) isa action-execution, has timestamp $review-time;
($user, $order) isa action-execution, has timestamp $order-time;
$review-time > $order-time;
} then {
$review has verified true;
};
rule review-unverified:
when {
$review isa review;
not { $review has verified true; };
} then {
$review has verified false;
};
rule book-recommendation-by-genre:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
$liked-book has genre $shared-genre;
$new-book has genre $shared-genre;
not { {
$shared-genre == "fiction";
} or {
$shared-genre == "nonfiction";
}; };
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule book-recommendation-by-author:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
($liked-book, $shared-author) isa authoring;
($new-book, $shared-author) isa authoring;
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule order-line-total-retail-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
not {
($promotion, $item) isa promotion-inclusion;
$promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
$line has quantity $quantity;
?line-total = $quantity * $retail-price;
} then {
$line has price ?line-total;
};
rule order-line-total-discounted-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
($best-promotion, $item) isa promotion-inclusion, has discount $best-discount;
$best-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
not {
($other-promotion, $item) isa promotion-inclusion, has discount > $best-discount;
$other-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
?discounted-price = round(100 * $retail-price * (1 - $best-discount)) / 100;
$line has quantity $quantity;
?line-total = $quantity * ?discounted-price;
} then {
$line has price ?line-total;
};
rule transitive-location:
when {
(location: $parent-place, located: $child-place) isa locating;
(location: $child-place, located: $x) isa locating;
} then {
(location: $parent-place, located: $x) isa locating;
};
Sample solution
match
$holiday-order isa order;
($holiday-order) isa action-execution,
has timestamp $order-time;
$holiday-sale isa promotion,
has code "HOL23",
has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
fetch
$holiday-order: id;
The ordering operators are also valid for strings, and function according to the Java string specification:
|
String matching operators
TypeQL includes two operators for string matching, denoted by the keywords contains
and like
. The contains
operator checks if one string contains another in a case-insensitive manner, while the like
operator can be used to match strings through Java regex patterns. Unlike the equality and ordering operators, the string matching operators can only be used to compare attribute values to string literals; they cannot be used to compare the values of two attributes.
The following query uses the contains
operator to retrieve a list of books with both "electron" and "diffraction" in the title.
match
$book isa book, has title $title;
$title contains "electron";
$title contains "diffraction";
fetch
$book: title;
{
"book": {
"title": [ { "value": "Interpretation of Electron Diffraction Patterns", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "Electron Backscatter Diffraction in Materials Science", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "hardback", "root": "entity" }
}
}
For non-Latin characters, the case insensitivity of the |
Meanwhile, the following query uses the like
operator to retrieve a list of books whose titles start with "the".
match
$book isa book, has title like "(?i)^the\s.*";
fetch
$book: title;
{
"book": {
"title": [ { "value": "The Hobbit", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "ebook", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Iron Giant", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "ebook", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Complete Calvin and Hobbes", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "hardback", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Odyssey", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "ebook", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Mummies of Urumchi", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Motorcycle Diaries: A Journey Around South America", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"title": [ { "value": "The Hitchhiker's Guide to the Galaxy", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
Write a Fetch query to retrieve the titles of books that contain "the" in a position other than the start.
You may find it useful to refer to the bookstore’s schema.
Schema
define
book sub entity,
abstract,
owns isbn-13 @key,
owns isbn-10 @unique,
owns title,
owns page-count,
owns genre,
owns price,
plays contribution:work,
plays publishing:published,
plays promotion-inclusion:item,
plays order-line:item,
plays rating:rated,
plays recommendation:recommended;
hardback sub book,
owns stock;
paperback sub book,
owns stock;
ebook sub book;
contributor sub entity,
owns name,
plays contribution:contributor,
plays authoring:author,
plays editing:editor,
plays illustrating:illustrator;
company sub entity,
abstract,
owns name;
publisher sub company,
plays publishing:publisher;
courier sub company,
plays delivery:deliverer;
publication sub entity,
owns year,
plays publishing:publication,
plays locating:located;
user sub entity,
owns id @key,
owns name,
owns birth-date,
plays action-execution:executor,
plays locating:located,
plays recommendation:recipient;
order sub entity,
owns id @key,
owns status,
plays order-line:order,
plays action-execution:action,
plays delivery:delivered;
promotion sub entity,
owns code @key,
owns name,
owns start-timestamp,
owns end-timestamp,
plays promotion-inclusion:promotion;
review sub entity,
owns id @key,
owns score,
owns verified,
plays rating:review,
plays action-execution:action;
login sub entity,
owns success,
plays action-execution:action;
address sub entity,
owns street,
plays delivery:destination,
plays locating:located;
place sub entity,
abstract,
owns name,
plays locating:located,
plays locating:location;
city sub place;
state sub place;
country sub place;
contribution sub relation,
relates contributor,
relates work;
authoring sub contribution,
relates author as contributor;
editing sub contribution,
relates editor as contributor;
illustrating sub contribution,
relates illustrator as contributor;
publishing sub relation,
relates publisher,
relates published,
relates publication;
promotion-inclusion sub relation,
relates promotion,
relates item,
owns discount;
order-line sub relation,
relates order,
relates item,
owns quantity,
owns price;
rating sub relation,
relates review,
relates rated;
action-execution sub relation,
relates action,
relates executor,
owns timestamp;
delivery sub relation,
relates deliverer,
relates delivered,
relates destination;
locating sub relation,
relates located,
relates location;
recommendation sub relation,
relates recommended,
relates recipient;
isbn sub attribute, abstract, value string;
isbn-13 sub isbn;
isbn-10 sub isbn;
title sub attribute, value string;
page-count sub attribute, value long;
genre sub attribute, value string;
stock sub attribute, value long;
price sub attribute, value double;
discount sub attribute, value double;
id sub attribute, value string;
code sub attribute, value string;
name sub attribute, value string;
birth-date sub attribute, value datetime;
street sub attribute, value string;
year sub attribute, value long;
quantity sub attribute, value long;
score sub attribute, value long;
verified sub attribute, value boolean;
timestamp sub attribute, value datetime;
start-timestamp sub attribute, value datetime;
end-timestamp sub attribute, value datetime;
status sub attribute, value string, regex "^(paid|dispatched|delivered|returned|canceled)$";
success sub attribute, value boolean;
rule review-verified-by-purchase:
when {
($review, $product) isa rating;
($order, $product) isa order-line;
($user, $review) isa action-execution, has timestamp $review-time;
($user, $order) isa action-execution, has timestamp $order-time;
$review-time > $order-time;
} then {
$review has verified true;
};
rule review-unverified:
when {
$review isa review;
not { $review has verified true; };
} then {
$review has verified false;
};
rule book-recommendation-by-genre:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
$liked-book has genre $shared-genre;
$new-book has genre $shared-genre;
not { {
$shared-genre == "fiction";
} or {
$shared-genre == "nonfiction";
}; };
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule book-recommendation-by-author:
when {
$user isa user;
$liked-book isa book;
{
($user, $order) isa action-execution;
($order, $liked-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $liked-book) isa rating;
$review has score >= 7;
};
$new-book isa book;
not { {
($user, $order) isa action-execution;
($order, $new-book) isa order-line;
} or {
($user, $review) isa action-execution;
($review, $new-book) isa rating;
}; };
($liked-book, $shared-author) isa authoring;
($new-book, $shared-author) isa authoring;
} then {
(recommended: $new-book, recipient: $user) isa recommendation;
};
rule order-line-total-retail-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
not {
($promotion, $item) isa promotion-inclusion;
$promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
$line has quantity $quantity;
?line-total = $quantity * $retail-price;
} then {
$line has price ?line-total;
};
rule order-line-total-discounted-price:
when {
($order) isa action-execution, has timestamp $order-time;
$line ($order, $item) isa order-line;
($best-promotion, $item) isa promotion-inclusion, has discount $best-discount;
$best-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
not {
($other-promotion, $item) isa promotion-inclusion, has discount > $best-discount;
$other-promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
};
$item has price $retail-price;
?discounted-price = round(100 * $retail-price * (1 - $best-discount)) / 100;
$line has quantity $quantity;
?line-total = $quantity * ?discounted-price;
} then {
$line has price ?line-total;
};
rule transitive-location:
when {
(location: $parent-place, located: $child-place) isa locating;
(location: $child-place, located: $x) isa locating;
} then {
(location: $parent-place, located: $x) isa locating;
};
Sample solution
match
$book isa book, has title like "(?i).+\sthe\s.*";
fetch
$book: title;
Write a Fetch query to retrieve the ISBN-13s of all books that are included in an order that has a status of "paid", "dispatched", or "delivered", without using a disjunction.
Sample solution
match
$book isa book;
$order isa order;
($book, $order) isa order-line;
$order has status like "^(paid|dispatched|delivered)$";
fetch
$book: isbn-13;