Define
As the name suggests, we use the define
keyword to develop the schema which represents the dataset stored in a TypeDB knowledge graph. We use define
to add new entities, relations, attributes and rules to the schema.
When defining the schema in a single schema.tql
file, the keyword define
needs to be included only once at the very top.
We can also use the define
keyword in the interactive mode of the TypeDB Console as well as the TypeDB Clients Java, Python and Node.js.
To try the following examples with one of the TypeDB clients, follows these Clients Guide.
Entity
An entity is a thing with a distinct existence in the domain. For example, organisation
, location
and person
. The existence of each of these entities is independent of any other concept in the domain.
Define an entity
To define a new entity, we use the sub
keyword followed by entity
.
Assign an attribute to an entity
We can assign any number of attributes to an entity. To do so, we use the owns
keyword followed by the attribute’s label.
Assign an attribute to an entity as a unique identifier
To assign a unique attribute to an entity, we use the owns
keyword followed by the attribute’s label and the @key
modifier.
This guarantees that no instances of email
may hold the same value among all instances of person
.
Entity to play a role
An entity can play a role in a relation. To define the role played by an entity, we use the plays
keyword followed by the role’s label.
Subtype an entity
We can define an entity to inherit all attributes owned and roles played by another entity. Let’s look at an example of subtyping the media
entity.
As you can see in the example above, when defining entities, what follows the sub
keyword can be a label previously given to another entity. By subtyping a parent entity, the children inherit all attributes owned and roles played by their parent.
In this example, comment
and media
are both considered to be subtypes of post
. Similarly video
and photo
are subtypes of media
and so are defined that way. Therefore, although not defined explicitly, we are right to assume that comment
, media
, video
and photo
all play the roles to
, in
and to
. However, the role attached
and the attributes caption
and file
are played and owned only by the media
entity and its subtypes. Similarly, the role to
and the attribute content
are played and owned only by the comment
entity.
The ability to subtype entities not only helps mirror the reality of the dataset as perceived in the real world but also enables automated reasoning using type hierarchies.
Define an abstract entity
There may be scenarios where a parent entity is only defined for other entities to inherit, and under no circumstance, do we expect to have any instances of this parent. To model this logic in the schema, we use the abstract
keyword. Let’s say in the example above, we would like to define both the post
and media
entity types to be abstract. By doing so, we are indicating that no data instances of these entity types are allowed to be created, leaving us only with instances of comment
, photo
and video
.
Relation
A relation describes how two or more things are in some way connected to each other. For example, friendship
and employment
. Each of these relations must relate to roles that are played by something else in the domain. In other words, relations are dependent on the existence of at least two other things.
Define a relation
To define a new relation, we use the sub
keyword followed by relation
.
define
employment sub relation;
To complete the definition of a relation, we must determine the roles that it relates to. To do so, we use the relates
keyword followed by the role’s label.
The roles employee
and employer
are now ready to be played by other concept types in the schema.
Role players of a relation
Entities, attributes, and even other relations can play a role in a relation. To do this we make use of the plays
keyword followed by the role’s label.
We have already seen how to define an entity to play a role and soon learn how to define an attribute to play a role as well. But what about a relation that plays a role in another relation?
Define a relation to play a role
Let’s go through a simple example of how a relation can play a role in another relation.
In the example above, the friendship
relation plays the role of the friendship
in the friend-request
relation. The other two role players in a friend-request
are 1) the person
who plays the requester
role and 2) another person
whole plays the respondent
role.
Once the friend-request
is accepted, then those two person
s play the role of friend
in the friendship
relation.
A relation with many role players
A relation can relate to any number of roles. The example below illustrates a three-way relation.
In the example above, the reaction
relation relates to three roles:
-
emotion
role played by anemotion
attribute. -
to
role played by apost
entity. -
by
role played by aperson
entity.
Assign an attribute to a relation
We can assign any number of attributes to a relation. To do so, we use the owns
keyword followed by the attribute’s label.
Assign an attribute to a relation as a unique identifier
To assign a unique attribute to a relation, we use the key
keyword followed by the attribute’s label.
This guarantees that no instances of reference-id
may hold the same value among all instances of employment
.
Subtype a relation
We can define a relation to inherit all attributes owned, and roles related to and played by another relation. Let’s take a look at an example of subtyping a friend-request
relation.
As you can see in the example above, when defining relations, what follows the sub
keyword can be a label previously given to another relation. By subtyping a parent relation, the children inherit all attributes owned and roles played by their parent.
In this example, friend-request
and membership-request
are both considered to be subtypes of request
and so are defined that way. Modelling these relations in this way, not only allows us to query for locations of birth and residence separately, but also allows us to query for all the associations that a given person has with a given location.
Note the use of the as
keyword. This is necessary to determine the correspondence between the role of the child and that of the parent.
The ability to subtype relations not only helps mirror the reality of the dataset as perceived in the real world but also enables automated reasoning using type hierarchies.
Define an abstract relation
There may be scenarios where a parent relation is only defined for other relations to inherit, and under no circumstance, do we expect to have any instances of this parent. To model this logic in the schema, we use the abstract
keyword. Let’s say in the example above, we would like to define the localisation
relation type to be abstract. By doing so, we are indicating that no data instances of the request
relation are allowed to be created, leaving us with instances of friend-request
and membership-request
only.
Attribute
An attribute is a piece of information that determines the property of an element in the domain. For example, name
, language
and age
. These attributes can be assigned to anything that needs them as a property.
Define an attribute
To define a new attribute, we use the sub
keyword followed by attribute
, value
and the type of the desired value.
The name
attribute is now ready to be owned by any other type in the schema.
The data types available in a TypeDB knowledge graph are:
-
long
: a 64-bit signed integer. -
double
: a double-precision floating point number, including a decimal point. -
string
: enclosed in double"
or single'
quotes -
boolean
:true
orfalse
-
datetime
: a date or date-time in the following formats:yyyy-mm-dd
yyyy-mm-ddThh:mm
yyyy-mm-ddThh:mm:ss
yyyy-mm-ddThh:mm:ss.f
yyyy-mm-ddThh:mm:ss.ff
yyyy-mm-ddThh:mm:ss.fff
The same attribute can be owned by different concept types.
A concept type can have any number of the same attribute that holds different values. In other words, a concept type has a many-to-many relation with its attributes.
An instance of a person
can have one instance of phone-number
, or two or three, … you get the idea.
Restrict attribute’s value by Regex
Optionally, we can specify a Regex that the values of an attribute type must conform to. To do this, we use the regex
keyword followed by a Java Regex Pattern.
Owners of an attribute
Entities, relations, and even attributes can own one or more attributes of their own. To do this we make use of the owns
keyword followed by the attributes’s label.
We have already seen how to assign an attribute to an entity and similarly to assign an attribute to a relation. But what about an attribute owning an attribute of its own?
Assign an attribute to another attribute
Let’s go through a simple example of how an attribute can own an attribute of its own.
In this example, attribute content
can be owned by, for instance, a post
entity. What this example aims to showcase is that the content
attribute, besides its own value, owns an attribute named language
which holds the name of the language the text is written in.
Define an attribute to play a role
An attribute can play a role in a relation. To define the role played by an attribute, we use the plays
keyword followed by the role’s label.
Subtype an attribute
We can define an attribute to inherit the valuetype, attributes owned and roles played by another attribute.
What this definition means is that birth-date
, start-date
and end-date
are all inherently subtypes of event-date
. They inherit the value type of event-date
as well as its contextuality.
The ability to subtype attributes not only helps mirror the reality of our dataset but also enables automated reasoning using type hierarchies.
Define an abstract attribute
There may be scenarios where a parent attribute is only defined for other attributes to inherit, and under no circumstance, do we expect to have any instances of this parent. To model this logic in the schema, we use the abstract
keyword. Let’s say in the example above, we would like to define the event-date
attribute type to be abstract. By doing so, we are indicating that no data instances of the event-date
attribute are allowed to be created, leaving us with instances of birth-date
, start-date
and end-date
.
Undefine
As the name suggests, we use the undefine
keyword to remove the definition of a type or its association with other types from the schema.
Undefine an attribute’s association
We can undefine the association that a type has with an attribute.
The query above, removes the attribute nickname
from the entity person
.
Undefine a relation
Undefining a relation inherently undefines all of its roles. Therefore when a relation is undefined any types that were playing roles in that relation will no longer play those roles. Given a marriage
relation type we can undefine it as shown below.
Undefine a Supertype
When the concept type to be undefined is a supertype to something else, we must first undefine all its subtypes before undefining the supertype itself.
Clients Guide
Summary
We learned that a TypeDB schema is essentially a collection of Entities, Relations, and Attributes - what we call the TypeDB Concept Types.
Relations have roles that interface with any concept (entities, relations, or attributes!) that can play those roles. This creates the structures and shape of the data. Meanwhile, any concept can own attributes, which represent the raw data values.
It is the modularity of these concept types and how they interact with one another that allows us to model complex datasets in an intuitive way that represents their true nature.
In the next section, we learn about one last addition to the schema - TypeQL Rules.