The data modeling REST API (DMS) in combination with the Cognite Python SDK offers more power and flexibility than the DML extension. They’re the preferred tools for managing industrial knowledge graphs in Cognite Data Fusion (CDF).
Basics
The data model format is in the GraphQL Schema Definition Language. Each data model has many types, consisting of properties, each with a specified type. Each type can contain properties that reference other types, forming a relationship. You can also specify the properties as a list of references to nodes of other types. Use! to indicate that a field is required and that each instance of the template must contain the value.
To add comments, enter "comment" above the field/type definition.
This example is a simple industry data model:
Equipmenttype has the propertiesid, andnameproperties.-
idmust be anIntegertype, and must exist on all nodes ofEquipment.namemust be aStringtype, and must exist on all nodes ofEquipment.
Equipmenttype has apartsrelationship to a list/array of one or moreParts.Equipmenttype has adocumentationrelationship to a list/array of one or moreDocuments. This is a reverse direct relation, meaning the direct relation property on theDocumentview is used for graph traversal.Parthas the propertiesidandname,idmust be anIntegertype, and must exist on all nodes ofPart.namemust be aStringtype, and must exist on all nodes ofPart.
Parthas adocumentationrelationship to a list/array of one or moreDocuments.Documenttype has the propertiesid,name, andFile.idmust be anIntegertype, and must exist on all nodes ofDocument.namemust be aStringtype, and must exist on all nodes ofDocument.sourcemust be aStringtype, and must exist on all nodes ofDocument.
Documenthas aequipmentrelationship to a single (piece of)Equipment.Equipment.namehas a comment/description (name of the piece of equipment).
@directRelation directive to the field.
Types and Interfaces
An object type in GraphQL is defined by using the keyword type, for exampletype Equipment defines an object type in GraphQL
called Equipment.
An interface type in GraphQL is defined by using the keyword interface, for example interface Equipment.
From a data querying or population perspective, there is no difference between a type being an object or interface. However,
only interface can be extended / implemented upon.
EquipmentInterface and EquipmentObject will here have the same query capabilities:
Enums
DML also supports GraphQL enum types, which can be defined using the keywordenum:
What happens in the background: In our DML, an object or interface type represents a view by default.
When a
@view directive isn’t specified, the view version will be managed by the GraphQL service. When a new
view version is needed due to breaking changes, the data model version will also have to be changed.
View versions can also be overriden by directives.We call types having a ‘@view’ directive for view types. A view type can extend from other view types, allowing for graphql inheritance, more in the next section.Extending types via inheritance
We rely on the inheritance rules as defined by GraphQL, so to extend another view type, that base view type has to be an interface. A view type can be extendable via inheritance by defining the type to be an interface. A view type can then extend the base type by usingimplements. You can also extend multiple interfaces by separating them with &.
This is an example of a view extending another view:
Descriptions
GraphQL descriptions are supported and will be converted to the corresponding description property on view, container and property definitions. Furthermore, we have syntax for setting thename of a view / container or a field. It is set by starting a line in the description
with @name.
The rest of the line will then be parsed as the name.
Example of GraphQL descriptions:
Spaces and naming collisions
When you create multiple data models in the same space with identical type names, they will interfere with each other and cause errors. To prevent this, ensure type names are unique within each space.Example collision scenario
Consider this scenario where you have two data models in spaceT:
Data model A:
How to avoid naming collisions
To prevent naming conflicts:- Use one data model per space - This eliminates the possibility of collisions.
- Use unique type names - If you need multiple data models in the same space, ensure all type names are unique across models.
Versioning
Every type is versioned, and the version changes when the view in the data model is updated with a breaking change. As of now, all changes to the structure of a type are considered breaking changes, but if you leave the type unchanged it will not get a new version. Since you can query each version of a data model individually, consumers are not directly affected by breaking changes.Relations
We support a number of different types of relations - they can point to a single target instance or multiple target instances, and they can be backed by either edges or direct relations. A relation with a single target instance, for exampledocument: Document, is backed by a direct relation. A direct relation is a container property storing a reference to another node. These can be used to describe both one to one and one to many relations - for example, an equipment can point to a single document describing it, but multiple equipments may point to the same document.
If you want to define a relation pointing to more than a single instance, you can create a field with a list data type, for example documents: [Document]. These can be used to describe both one to many and many to many relations - for example, an equipment can point to multiple documents describing it and multiple equipments can point to the same documents.
These relations are by default backed by edges, and they need to be ingested as separate instances. It is possible to specify that relation should be backed by a list of direct relations instead by using the @directRelation directive.
What happens in the background:
documents: [Document] will generate a view connection property that we call a relation in graphql. A relation is defined by the:- relational direction (edge direction), which by default is OUTWARDS
- the edge.type to follow. The default is set to
{your_typename}.{your_fieldname}. - the space is by default set to be the same as the view that the field resides in.
Categories of types
The followingtypes are available:
- Primitives - simple types like
String,Int,Int64,Float,Boolean,JSONObject,TimeSeries, andTimestamp. - User defined - any other type that is defined in the data model. In the example above,
ActorandMovieare examples of user defined types, forming relationships between types.
[String]) or in singular form (for example String) through [...].
Primitive data types
Primitive data types are mapped as following:| GraphQL name | API name | Description |
|---|---|---|
| String | text | |
| Int or Int32 | int32 | 32-bit integer number |
| Int64 | int64 | 64-bit integer number |
| Float or Float64 | float64 | 64-bit number encoded in IEEE 754 |
| Float32 | float32 | 32-bit number encoded in IEEE 754 |
| Timestamp | timestamp | Timestamp encoded in ISO 8601 |
| JSONObject | json | JSON encoded data |
| Date | date | Date encoded in ISO 8601, but without time |
| Boolean | boolean |
CDF native resource types
Primitive data types are mapped as following:| GraphQL name | API name | Description | Supported |
|---|---|---|---|
| File | ✅ | ||
| TimeSeries | ✅ | ||
| Sequence | ✅ |
input and extends despite the feature being available in GraphQL.
How GraphQL SDL concepts are mapped to data models API
The main goal of the DML is to re-use concepts from the GraphQL schema definition language to the extent possible. However, the GraphQL SDL is designed to describe a schema, while we need to translate it into an implementation. There are multiple implementations conforming to the same GraphQL schema. For convenience, the translation from a GraphQL schema to a set of industrial knowledge graph schema components - containers and views - is based on sane defaults. However, this behavior can be overridden as needed by using directives.Specification of directives
The following is a list of the directive definitions, with descriptions. There are more extensive guides describing how each is used, and the purpose they serve, in the advanced data modeling guides.Advanced: mapping and importing fields
A view type can also map directly to properties in a container using the @mapping directive. Thus, the fields of a type defined in GraphQL can be a mix of imported properties and mapped properties. Fields that are imported via inheritance can not be mapped. Fields that are mapped using the mapping directive, must exist. In other words, there are no auto-generation of fields mapped. Fields that aren’t “imported” are, by default, mapped to a generated container with the same name as the type name. For example above,EquipmentObject will create a view and a container with the same externalId.