> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognite.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spaces, instances, direct relations

> Learn how to construct an industrial knowledge graph using spaces, instances, nodes, edges, and direct relations in CDF.

## Space

A **space** can contain both **schemas** and **instances**. It is an efficient resource to help organize your graph. It functions as a namespace, and lets you choose identifiers without interference from other spaces.

```mermaid theme={"languages":{"custom":["/_languages/kuiper.json","../_languages/kuiper.json"]}}
graph TB
  subgraph "Space X"
  X1((A)) --> X2((B))
  end
  subgraph "Space Y"
  Y2((B))
  end
```

Spaces serve as a scope for **governance** and **access control** facilitating a structured approach to data management. You can use CDF user groups and capabilities to define who has access to read from and write to a space. You can, for example, create a data model in a protected space to prevent it from being changed, and then create instances in a space where users can read and write to the data.

To delete a space, you have to remove all schema resources assigned to it first.

## Instance

The term **instance** is an umbrella term for **nodes** and **edges**.

* **Nodes** can represent anything, for example, real-world objects like *pumps*.

* **Edges** describe relationships between nodes.

Every instance has a set of core properties, and many of the properties apply to both nodes and edges:

| Property        | Description                                               | Node | Edge |
| --------------- | --------------------------------------------------------- | ---- | ---- |
| space           | Which space the node/edge belongs to.                     | x    | x    |
| externalId      | The identifier of the node/edge.                          | x    | x    |
| type            | A direct relation pointing to the type node/edge.         | x    | x    |
| startNode       | A direct relation pointing to the start node.             |      | x    |
| endNode         | A direct relation pointing to the end node.               |      | x    |
| createdTime     | When the node/edge was created.                           | x    | x    |
| lastUpdatedTime | When the node/edge was last updated.                      | x    | x    |
| version         | A number incremented every time the instance is modified. | x    | x    |

When you create an instance, the version is set to 1. Any changes to the instance increase the version by increments of 1. For example, an instance with version 3 indicates that the instance has been updated twice.

<Note>
  Update requests that don't update any instance properties don't increment the `version` or `lastUpdatedTime` of the instance.
</Note>

<Note>
  Edges depend on their associated start and end nodes. When a node is deleted, any edges connected to it are also removed.
</Note>

Edges can **span** spaces. They reside in a specific space but can link to nodes in other spaces.

```mermaid theme={"languages":{"custom":["/_languages/kuiper.json","../_languages/kuiper.json"]}}
graph LR
  subgraph "Space Y"
  X1((B))
  end
  subgraph "Space X"
  E(E)
  Y2((A)) --- E
  E --> X1
  end
```

### External IDs

Every instance is assigned an **external ID** that must be unique within a space. A fully qualified external ID consists of both the space and the external ID, for example: `{"space": "mySpace", "externalId": "myNode"}`. You can also use the short form: `["mySpace", "myNode"]`.

The **maximum length** of an external ID is 255 characters, and **null bytes** are not allowed within the ID.

## Direct relations vs. edges

You can express relationships to nodes using **edges** or a special type of property called a **direct relation**. A direct relation is a property holding a reference to a node or list of nodes, and is similar to a *foreign key* in relational models. Edges and direct relations have different characteristics:

|                                                                                                                                        | Direct relations | Edges |
| -------------------------------------------------------------------------------------------------------------------------------------- | :--------------: | :---: |
| Can have properties of their own.                                                                                                      |        No        |  Yes  |
| Can be traversed recursively.                                                                                                          |        No        |  Yes  |
| Can restrict which [container](/cdf/dm/dm_concepts/dm_containers_views_datamodels#containers) the target node must have data in.       |        Yes       |   No  |
| Cheap, supporting a large number of direct relations with minimal overhead.                                                            |        Yes       |   No  |
| Relatively costly, making direct relations a consideration for large quantities, as they count toward instance limits.                 |        No        |  Yes  |
| Can enforce that a set of edges form a tree or a [Directed Acyclic Graph (DAG)](https://en.wikipedia.org/wiki/Directed_acyclic_graph). |        No        |  Yes  |
| Can traverse reverse direction of one-to-many relationships.\*                                                                         |        No        |  Yes  |

If you have a list of direct relations, you can't traverse the reverse direction of a one-to-many relationship. Instead, you have to do a lookup in the reverse direction. For example, in the Cognite Core model, `CogniteActivity` has a property `assets` which is a list of direct relations to `CogniteAsset`.

To find all activities that have a specific asset, you can't create a query that starts from the asset(s). Instead, you have to query all activities and filter on the asset(s) you want. If the relation was modeled as an edge, you could find all activities by traversing the edge from the asset(s).

## Type nodes

In your graph, nodes can represent anything from physical entities to abstract concepts like a comment or the *type* of a physical entity. Every instance has a `type`
property, a direct relation pointing to the node that defines its intended type.

For example, a node representing a physical pump can have the `type` property pointing to a "Pump" node. Or an edge representing a pipe can have the `type` property pointing to a "FlowsTo" node.

As type systems grow in size and complexity, the importance of organization and governance increases. To manage type systems effectively, we recommend that you organize them in dedicated spaces within your graph. In the example graph below, the type nodes are in a dedicated `types` space. Depending on the complexity of your type system, you may want to consider organizing them across multiple spaces.

<Note>
  You can't delete a type node when it has instances pointing to it.
</Note>

See [Node type support in data modeling](/cdf/integration/guides/transformation/write_sql_queries#write-to-specific-properties-in-data-modeling) to populate the type property of nodes and edges using Transformations.

## Example knowledge graph

This example illustrates what a small knowledge graph could look like. It displays nodes, direct
relations, and edges to represent a pump directing liquid through pipes into a set of valves and
where someone has added a comment about the pump:

```mermaid theme={"languages":{"custom":["/_languages/kuiper.json","../_languages/kuiper.json"]}}
graph LR;
  subgraph "space: equipment"
    Pump(("Pump<br>externalId: pump42<br>type: [types, pump]"))
    Valve1(("Valve<br>externalId: valve1<br>type: [types, valve]"))
    Valve2(("Valve<br>externalId: valve2<br>type: [types, valve]"))

    PumpValve1Edge("FlowsTo <br> externalId: 42To1 <br> type: [types, flows-to] <br> startNode: [equipment, pump42] <br> endNode: [equipment, valve1]")
    PumpValve2Edge("FlowsTo <br> externalId: 42To2 <br> type: [types, flows-to] <br> startNode: [equipment, pump42] <br> endNode: [equipment, valve2]")

    Pump---PumpValve1Edge
    Pump---PumpValve2Edge
    PumpValve1Edge-->Valve1
    PumpValve2Edge-->Valve2
  end
  subgraph "space: users"
    User(("User<br> externalId: engineer3 <br> type: [types, user]"))
    Comment(("Comment<br>externalId: cmnt144 <br> type: [types, comment]<br>user: [users, engineer3]<br>isCommentOn: [equipment, pump42]"))

    Comment-.->User
    Comment-.->Pump

  end
  subgraph "space: types"
    direction LR
    PumpType(("PumpType<br>externalId: pump"))
    ValveType(("ValveType<br>externalId: valve"))
    CommentType(("CommentType<br>externalId: comment"))
    UserType(("UserType<br>externalId: user"))

    FlowsToType(("FlowsToType<br>externalId: flows-to"))

    Pump-.->PumpType
    Valve1-.->ValveType
    Valve2-.->ValveType
    PumpValve1Edge-.->FlowsToType
    PumpValve2Edge-.->FlowsToType
    User-.->UserType
    Comment-.->CommentType
  end
```

### Simplified view

Here's a simplified view of the above graph, displaying only the nodes and edges:

```mermaid theme={"languages":{"custom":["/_languages/kuiper.json","../_languages/kuiper.json"]}}
graph TB;
  subgraph "space: equipment"
    Pump(("Pump<br>externalId: pump42<br>type: [types, pump]"))
    Valve1(("Valve<br>externalId: valve1<br>type: [types, valve]"))
    Valve2(("Valve<br>externalId: valve2<br>type: [types, valve]"))

    PumpValve1Edge("FlowsTo <br> externalId: 42To1 <br> type: [types, flows-to] <br> startNode: [equipment, pump42] <br> endNode: [equipment, valve1]")
    PumpValve2Edge("FlowsTo <br> externalId: 42To2 <br> type: [types, flows-to] <br> startNode: [equipment, pump42] <br> endNode: [equipment, valve2]")

    Pump---PumpValve1Edge
    Pump---PumpValve2Edge
    PumpValve1Edge-->Valve1
    PumpValve2Edge-->Valve2
  end
  subgraph "space: users"
    User(("User<br> externalId: engineer3 <br> type: [types, user]"))
    Comment(("Comment<br>externalId: cmnt144 <br> type: [types, comment]<br>user: [users, engineer3]<br>isCommentOn: [equipment, pump42]"))
  end
  subgraph "space: types"
    direction LR
    PumpType(("PumpType<br>externalId: pump"))
    ValveType(("ValveType<br>externalId: valve"))
    CommentType(("CommentType<br>externalId: comment"))
    UserType(("UserType<br>externalId: user"))

    FlowsToType(("FlowsToType<br>externalId: flows-to"))
  end
```
