Constructing a graph¶
This article outlines how to use spaces and instances to construct an industrial knowledge graph.
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. Also, it serves as a scope for governance and access control facilitating a structured approach to data management.
graph TB
subgraph "Space X"
X1((A)) --> X2((B))
end
subgraph "Space Y"
Y2((B))
end
Instance¶
The term instance is an umbrella term for nodes and edges. 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 was last updated. | x | x |
version | A number incremented every time the instance is modified. | x | x |
:::note
Edges depend on their associated start and end nodes. When a node is deleted, any edges connected to it are also removed.
:::
Edges can span spaces. They reside in a specific space but can link to nodes in other spaces.
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, 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 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). | No | Yes |
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. :::
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:
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:
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