Officially out now: The TypeDB 3.0 Roadmap

Lesson 3.3: Fetching inferred data

Rule inference

Try running the following query, which retrieves a particular user’s location.

match
$user isa user, has id "u0003";
(located: $user, location: $place) isa locating;
fetch
$place: name;

studio run Run

{
    "place": {
        "name": [ { "value": "Newark", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
        "type": { "label": "city", "root": "entity" }
    }
}

As we can see from the results, the user is located in Newark. Now, toggle on the infer option and run the query again.

If you are using TypeDB Studio, you can find out how to toggle the infer option on and off in Lesson 2.2. If you are using a different client, then you can find out how to provide this flag for queries in the rule inference section of the TypeDB Manual.

You should see the following results.

{
    "place": {
        "name": [ { "value": "Newark", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
        "type": { "label": "city", "root": "entity" }
    }
}
{
    "place": {
        "name": [ { "value": "New Jersey", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
        "type": { "label": "state", "root": "entity" }
    }
}
{
    "place": {
        "name": [ { "value": "United States", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
        "type": { "label": "country", "root": "entity" }
    }
}

We haven’t inserted any new data or changed our query, but TypeDB is now generating additional results! This is due to TypeDB’s built-in rule inference engine, which allows it to generate new data based on rules defined in the schema. We’ll learn how to define rules in Lesson 5.4, but for now let’s take a quick look at the one we’ve made use of for the previous query.

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;
    };

The structure of this rule tells us that locating relations are transitive. Our data contains the following information encoded in locating relations:

  • The user with ID "u0003" is located in Newark.

  • Newark is located in New Jersey.

  • New Jersey is located in the United States.

Examining these facts, it is obvious to us that the user is located in the US, as we are able to deduce this fact. With the above rule, TypeDB is able to make the same deduction!

Using inferred data

Once a rule is defined and rule inference is switched on, we can use the inferred data as part of larger queries. In the following query, we retrieve the list of books ordered by users located in the US.

match
$us isa country, has name "United States";
(location: $us, located: $user) isa locating;
(executor: $user, action: $order) isa action-execution;
(order: $order, item: $book) isa order-line;
fetch
$book: title;

studio run Run

{
    "book": {
        "title": [ { "value": "The Iron Giant", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "ebook", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "The Hobbit", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "ebook", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Physical Principles of Electron Microscopy: An Introduction to TEM, SEM, and AEM", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "ebook", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Under the Black Flag: The Romance and the Reality of Life Among the Pirates", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "hardback", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Hokusai's Fuji", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "paperback", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Pride and Prejudice", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "paperback", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Business Secrets of The Pharoahs", "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" }
    }
}
{
    "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": "Dune", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "ebook", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "Great Discoveries in Medicine", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "paperback", "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": "Interpretation of Electron Diffraction Patterns", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "paperback", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "To Kill a Mockingbird", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
        "type": { "label": "paperback", "root": "entity" }
    }
}
{
    "book": {
        "title": [ { "value": "One Hundred Years of Solitude", "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" }
    }
}

Try running this query, once with the infer option toggled on and once with it off. If rule inference is switched off, we retrieve no results whatsoever! That is because we don’t have any users recorded as being located in the US in our data. Instead, they are recorded as being located in cities, with the cities recorded as being located in states, and the states recorded as being located in the US. The means the above query will only work with rule inference switched on.

Exercise

Write a query to retrieve the names of cities located in the United States. Run it once with rule inference switched off, and again with it switched on.

Hint

You will need to use the following types in your query: country, name, locating, city.

Sample solution
match
$city isa city;
$us isa country, has name "United States";
(located: $city, location: $us) isa locating;
fetch
$city: name;

studio run Run

Benefits of rule inference

Rule inference is a powerful tool that allows us to avoid redundancy in our data. Imagine if we stored the states and countries that users were located in on disk instead of generating them by rule inference. What would then happen if a user’s location changed? We would need to individually update their city, state, and country, despite the fact that both state and country depend only on the city. It would also be possible for data to be only partially updated, potentially leading to inconsistent data states. By using rule inference, we can ensure that we only have to update our data in one place, and data inconsistencies are prevented.

Rule inference also provides us with a number of additional benefits:

  • Rule inference functions on deductive reasoning, so results are always well-defined and certain.

  • Rules are resolved at query time, so inference always uses the most up-to-date data.

  • Inferred data is only generated once, so results returned are never redundant.

  • Rules can be activated sequentially, leading to complex emergent behaviour.

We will explore rule inference in more detail in Lesson 10. In the meantime, we will continue to make use of it in our queries throughout this course.

Throughout the remainder of this course, many queries will make use of rule inference. Ensure that the infer option is toggled on from this point onwards, or some queries may not generate expected results.