Inferring data
How to use inference
Inference is enabled as a Read transaction option.
TypeDB Studio
To send a request with inference enabled in TypeDB Studio follow these steps:
-
Ensure the Session type (
schema
/data
) switch is set todata
(next to the database dropdown). -
Ensure the Transaction type (write / read) switch is set to
read
. -
Ensure the infer button (next to the transaction type switch) is pushed (shown in green text).
-
Click the
+
icon at the top of the Text editor panel. -
Copy the TypeQL query into the Text editor panel.
-
Click the green "play" button.
TypeDB Console
Set the infer
option to true
when starting the read transaction. For example:
transaction typedb data read --infer true
TypeDB Drivers
Set the infer
option to True
when starting the read transaction.
For example (in Python):
typedb_options = TypeDBOptions() # Initialising a new set of options
typedb_options.infer = True # Enabling inference in this new set of options
with session.transaction(TransactionType.READ, typedb_options) as transaction:
Example
In the IAM database there are multiple rules, but we will use the one described at the IAM schema explanation page.
rule add-view-permission:
when {
$modify isa action, has name "modify_file";
$view isa action, has name "view_file";
$ac_modify (object: $obj, action: $modify) isa access;
$ac_view (object: $obj, action: $view) isa access;
(subject: $subj, access: $ac_modify) isa permission;
} then {
(subject: $subj, access: $ac_view) isa permission;
};
By default, the IAM dataset used in the Quickstart guide sets permissions only for the
modify_file
action.
But the IAM schema has the rule called add-view-permission
(see above) to infer permission to view_file
access
from the modify_file
permission for the same file. The view_file
action access permission does not exist in the
database, but it can be inferred by the rule.
To do so, let’s use the following query:
match
$p isa person, has full-name "Kevin Morrison";
$o isa object, has path $o-path;
$a isa action, has name "view_file";
$ac(object: $o, action: $a) isa access;
$pe(subject: $p, access: $ac) isa permission;
get $o-path;
The above query should return path
values for most files if the inference option is enabled. Without the
inference enabled the query should not return any results (as the default IAM dataset contains no permissions for
access with view_file
action).
Query explanation
The example is a get
query that does the following:
-
Finds
person
entity ($p
) with an attributefull-name
equal to theKevin Morrison
string value. -
Finds all
object
entities ($o
) with apath
attribute ($o-path
). -
Finds
action
entity ($a
) withname
ofview-file
. -
Finds
access
relation ($ac
) that relates$o
(asobject
) to$a
(asaction
). -
Finds all
permission
relations that relate$p
(assubject
) to$ac
(asaccess
). -
Filters the results to receive only the
$o-path
variable that complies with all the statements above.
In short, it returns path
attributes for every object
that person
with a full-name
of Kevin Morrison
has
permission to access with action
with the name
of view_file
.
Explain query
There is specific type of query to use with the inferred results if we want them explained by a TypeDB server.
An Explain query does not use any TypeQL syntax.
When we get a result of a Get query that was performed with both inference
and explain
options enabled we
can use an Explain query to request additional information on exactly how the instances of data were inferred.
To do that use the explainables
method on the get
query result (ConceptMap
). It returns a stream of explainable
objects. Send an explainable
object with an Explain query to get a stream of explanations
.
Every explanation
include information about what rule was used to obtain this inferred result,
condition of the rule, conclusion of the rule, and variable mapping.
Python example
The following code (provided with a TypeDB server with IAM database from
Quickstart guide) can infer view_file
permission for multiple files for a single
user and explain every inferred result. Basically, we repeat the previous example and then request explanation of
relation $pe
.
from typedb.driver import TypeDB, SessionType, TransactionType, TypeDBOptions
with TypeDB.core_driver("0.0.0.0:1729") as driver: # Connect to TypeDB server
with driver.session("iam", SessionType.DATA) as session:
print("\nRequest #1: Explain query — Files that Kevin Morrison has view access to (with explanation)")
typedb_options = TypeDBOptions() # Initialising a new set of options
typedb_options.infer = True # Enabling inference in this new set of options
typedb_options.explain = True
with session.transaction(TransactionType.READ, typedb_options) as transaction:
typeql_read_query = "match $p isa person, has full-name $p-fname; $o isa object, has path $o-path;" \
"$a isa action, has name 'view_file'; $ac(object: $o, action: $a) isa access;" \
"$pe(subject: $p, access: $ac) isa permission; $p-fname = 'Kevin Morrison';" \
"get $o-path; sort $o-path asc;"
iterator = transaction.query().get(typeql_read_query)
i = 0
for item in iterator: # Iterating through results
i += 1
explainable_relations = item.explainables().relations()
e = 0
for explainable in explainable_relations:
e += 1
explain_iterator = transaction.query().explain(explainable_relations[explainable])
ex = 0
for explanation in explain_iterator:
ex += 1
print("\nRead result #:", i, ", File path:", item.get(cVar("o-path")).as_attribute().get_value())
print("Explainable #:", e, ", Explained variable:", explainable)
print("Explainable object:", explainable_relations[explainable])
print("Explainable part of query:", explainable_relations[explainable].conjunction())
print("Explanation #:", ex)
print("\nRule: ", explanation.rule().get_label())
print("Condition: ", explanation.condition())
print("Conclusion: ", explanation.conclusion())
print("Variables used in explanation: ", explanation.variable_mapping())
print("----------------------------------------------------------")
The script above runs the query from the example in the previous section. The inference option provides
the result of 10 files (by default in the IAM database from the Quickstart guide).
And explain
option enables the explainables
to be received and used in the explain queries (one explain query
for each result that needs to be explained).
Output
The result should be similar to the following:
Read result #: 10 , File path: zlckt.ts Explainable #: 1 , Explained variable: pe Explainable object: <typedb.concept.answer.concept_map._ConceptMap.Explainable object at 0x105cb34f0> Explainable part of query: { $pe (subject:$p, access:$ac); $pe isa permission; } Explanation #: 1 Rule: add-view-permission Condition: [_1/_StringAttribute[name:0x836f800328000b6d6f646966795f66696c65]][_2/_StringAttribute[name:0x836f8003280009766965775f66696c65]][_3/_Relation[permission:0x847080038000000000000001]][ac_modify/_Relation[access:0x8470800a8000000000000003]][ac_view/_Relation[access:0x8470800a8000000000000011]][modify/_Entity[operation:0x826e800c8000000000000001]][obj/_Entity[file:0x826e80098000000000000004]][subj/_Entity[person:0x826e80018000000000000001]][view/_Entity[operation:0x826e800c8000000000000000]] Conclusion: [_/_Relation[permission:0x847080037fffffffffffffff]][_permission/_RelationType[label: permission]][_permission:access/_RoleType[label: permission:access]][_permission:subject/_RoleType[label: permission:subject]][ac_view/_Relation[access:0x8470800a8000000000000011]][subj/_Entity[person:0x826e80018000000000000001]] Variables used in explanation: {'p': {'subj'}, 'ac': {'ac_view'}, 'pe': {'_'}} ----------------------------------------------------------
Explanation parsing
Get label
The explanation.rule().get_label()
method returns the name of the rule that was used for this particular inference,
hence the result of which is being explained:
add-view-permission
Variable mapping
The explanation.variable_mapping()
method returns mapping of the variable names in the query with variable names in
the rule:
{'p': {'subj'}, 'ac': {'ac_view'}, 'pe': {'_'}}
Condition
The explanation.condition()
method returns the condition of the rule written with the exact matched instances of data.
For the rule condition defined as:
$modify isa action, has name "modify_file"; $view isa action, has name "view_file"; $ac_modify (object: $obj, action: $modify) isa access; $ac_view (object: $obj, action: $view) isa access; (subject: $subj, access: $ac_modify) isa permission; \
We got the condition explained with particular instances from the IAM dataset:
[_1/_StringAttribute[name:0x836f800328000b6d6f646966795f66696c65]] [_2/_StringAttribute[name:0x836f8003280009766965775f66696c65]] [_3/_Relation[permission:0x847080038000000000000001]] [ac_modify/_Relation[access:0x8470800a8000000000000003]] [ac_view/_Relation[access:0x8470800a8000000000000011]] [modify/_Entity[operation:0x826e800c8000000000000001]] [obj/_Entity[file:0x826e80098000000000000004]] [subj/_Entity[person:0x826e80018000000000000001]] [view/_Entity[operation:0x826e800c8000000000000000]]
The example above contains additional line breakers for convenience. The syntax of the condition is similar to the following pattern:
[<rule_variable_label>/<RootType>[<Type>:<IID>]]
Instead of a <RootType> placeholder we can get one of this:
|
Those are exact instances of data that were matched by the rule. For example, obj
is a file
type entity that has
an attribute of path
type with the value zlckt.ts
. We didn’t get the path
in the explanation because it wasn’t
mentioned in the rule, but was able to obtain it by the API call from the get query result:
item.get(cVar("o-path")).as_attribute().get_value())
Conclusion
The explanation.conclusion()
method returns the conclusion of the rule written with the exact instances of data
(including the inferred instance of data that exists only virtually — as a result of the inference).
For the rule condition defined as:
(subject: $subj, access: $ac_view) isa permission;
We got the conclusion explained with particular instances from the IAM dataset:
[_/_Relation[permission:0x847080037fffffffffffffff]] [_permission/_RelationType[label: permission]] [_permission:access/_RoleType[label: permission:access]] [_permission:subject/_RoleType[label: permission:subject]] [ac_view/_Relation[access:0x8470800a8000000000000011]] [subj/_Entity[person:0x826e80018000000000000001]]
The example above contains additional line breakers for convenience. The syntax of the condition is similar to the following pattern:
[<rule_variable>/<RootType>[<Type>:<IID>]]
Instead of a <RootType> placeholder we can get one of this:
|
Inference optimization
These are general tips for making queries with reasoning execute faster:
-
Adding a limit to the query. Without a limit, the reasoning engine is forced to explore all possible ways to answer the query exhaustively. If we only need 1 answer, adding
limit 1;
to the get query can significantly improve query times. -
Using the same transaction for multiple reasoning queries. Because inferred data is cleared between transactions, running the same or similar queries within one transaction can reuse previously inferred data. Combined with a limit on the query, it might be possible to avoid having to do any new reasoning at all.
-
For complex queries, it can also be beneficial to add more CPU cores, as the reasoning engine is able to explore more paths in the database concurrently.