Skip to content

Commit 5f02e5b

Browse files
Merge to master (#1037)
## Goal Add graph and hypergraph use case pages (#1036)
1 parent dfd3c04 commit 5f02e5b

File tree

4 files changed

+459
-0
lines changed

4 files changed

+459
-0
lines changed
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
= Graph database
2+
:Summary: How TypeDB works as a more advanced graph database
3+
:keywords: typedb, graph database, property graph, neo4j, cypher, labeled property graph
4+
:test-typeql: linear
5+
6+
If you've worked with graphs or graph databases like Neo4j, you already think in terms of nodes and edges. TypeDB shares the core intuition that relationships are first-class citizens, but its model goes further: entities and relations are fully typed, relationships carry named roles, and a strict schema validates every write.
7+
8+
This page maps graph concepts to TypeDB, and shows you how TypeDB goes above and beyond property graph models. We'll work through a concrete example — a companies ledger tracking companies, their directors, and ownership stakes.
9+
10+
== Mapping property graph concepts to TypeDB
11+
12+
[cols="1,1,2"]
13+
|===
14+
| Property graph | TypeDB | Notes
15+
16+
| Node
17+
| Entity
18+
| Typed instances with attributes. **No labels** - the type _is_ the classification.
19+
20+
| Label
21+
| Type
22+
| Instead of attaching labels, you define types in the schema. Types can be organized in hierarchies, eg. `organization` (abstract) -> [`company`, `nonprofit`]. There are 3 groups of types: Entity types, Relation types, and Attribute types.
23+
24+
| Property
25+
| Attribute
26+
| Owned by entity or relation types. Value-typed (`string`, `long`, `double`, `datetime`, ...).
27+
28+
| Edge
29+
| Relation with roles
30+
| A relation connects players through named roles, not just source -> target. Relation types declare which role(s) they `relates`, which are in turn added to other types using `plays`.
31+
32+
| Edge property
33+
| Relation-owned attribute
34+
| Relations own attributes directly.
35+
36+
| Traversal
37+
| Pattern matching
38+
| TypeQL `match` clauses describe the subgraph you want; the engine finds all matches.
39+
|===
40+
41+
In TypeDB, entity, relation, and attribute types make up the schema, while entity, relation, and attribute _instances_ make up the data.
42+
43+
=== Example: a companies ledger
44+
45+
Let's model companies, people who direct them, and the ownership stakes between them.
46+
47+
**Cypher (property graph)**
48+
49+
In Cypher, you directly insert the data without any schema:
50+
51+
[,cypher]
52+
----
53+
CREATE (acme:Company {name: "Acme Corp", jurisdiction: "US", incorporated: date("2019-03-15")})
54+
CREATE (globex:Company {name: "Globex Inc", jurisdiction: "UK", incorporated: date("2021-07-01")})
55+
CREATE (initech:Company {name: "Initech Ltd", jurisdiction: "US", incorporated: date("2015-11-20")})
56+
57+
CREATE (alice:Person {name: "Alice Park"})
58+
CREATE (bob:Person {name: "Bob Rivera"})
59+
60+
CREATE (alice)-[:DIRECTS]->(acme)
61+
CREATE (alice)-[:DIRECTS]->(globex)
62+
CREATE (bob)-[:DIRECTS]->(initech)
63+
64+
CREATE (acme)-[:OWNS {stake_percentage: 51.0}]->(globex)
65+
CREATE (acme)-[:OWNS {stake_percentage: 30.0}]->(initech)
66+
----
67+
68+
This is simple and readable — but nothing in the database enforces which node types can appear on either end of an edge, or what properties an edge should carry. You could accidentally create `(alice)-[:OWNS]->(bob)` and the database would accept it.
69+
70+
**TypeQL**
71+
72+
In TypeDB, we define a schema first:
73+
74+
[,typeql]
75+
----
76+
#!test[schema]
77+
define
78+
attribute name, value string;
79+
attribute jurisdiction, value string;
80+
attribute incorporation-date, value date;
81+
attribute stake-percentage, value double;
82+
83+
entity company,
84+
owns name @key,
85+
owns jurisdiction,
86+
owns incorporation-date @card(1), # required
87+
# i.e. instances of company can use directorship relations via the directed role
88+
plays directorship:directed,
89+
plays ownership:owner,
90+
plays ownership:subsidiary;
91+
92+
entity person,
93+
owns name,
94+
plays directorship:director;
95+
96+
relation directorship,
97+
relates director,
98+
relates directed;
99+
100+
relation ownership,
101+
relates owner,
102+
relates subsidiary,
103+
owns stake-percentage;
104+
----
105+
106+
Then, insert data:
107+
108+
[,typeql]
109+
----
110+
#!test[write, commit]
111+
insert
112+
$acme isa company,
113+
has name "Acme Corp",
114+
has jurisdiction "US",
115+
has incorporation-date 2019-03-15;
116+
$globex isa company,
117+
has name "Globex Inc",
118+
has jurisdiction "UK",
119+
has incorporation-date 2021-07-01;
120+
$initech isa company,
121+
has name "Initech Ltd",
122+
has jurisdiction "US",
123+
has incorporation-date 2015-11-20;
124+
125+
$alice isa person, has name "Alice Park";
126+
$bob isa person, has name "Bob Rivera";
127+
128+
$d1 isa directorship (director: $alice, directed: $acme);
129+
$d2 isa directorship (director: $alice, directed: $globex);
130+
$d3 isa directorship (director: $bob, directed: $initech);
131+
132+
$o1 isa ownership (owner: $acme, subsidiary: $globex),
133+
has stake-percentage 51.0;
134+
$o2 isa ownership (owner: $acme, subsidiary: $initech),
135+
has stake-percentage 30.0;
136+
----
137+
138+
The schema validates that only a `person` can be a `director` and only a `company` can be an `owner` or `subsidiary`. The mistake `(owner: $alice, subsidiary: $bob)` would be rejected at write time.
139+
140+
_TypeDB enforces the structure of your graph, so your application doesn't have to._
141+
142+
=== Querying: find a company's directors
143+
144+
**Cypher:**
145+
[,cypher]
146+
----
147+
MATCH (person)-[:DIRECTS]->(company:Company {name: "Acme Corp"})
148+
RETURN person.name
149+
----
150+
151+
**TypeQL:**
152+
[,typeql]
153+
----
154+
#!test[read, count=1]
155+
match
156+
$company isa company, has name "Acme Corp";
157+
$dir isa directorship (director: $person, directed: $company);
158+
$person has name $name;
159+
----
160+
161+
The queries look similar — both follow edges from a company to its directors.
162+
163+
== What TypeDB adds beyond property graphs
164+
165+
=== Type inheritance and polymorphism
166+
167+
In a property graph, you might give a node multiple labels — `:Company:Public` or `:Company:Private` — but there's no enforced hierarchy. In TypeDB, types form a tree. You could extend the ledger schema with subtypes:
168+
169+
[,typeql]
170+
----
171+
define
172+
entity company @abstract;
173+
entity public-company sub company;
174+
entity private-company sub company;
175+
----
176+
177+
Now querying `company` returns all public and private companies — without listing subtypes!
178+
179+
This works for relations too. You could subtype `ownership` into `majority-ownership` and `minority-ownership`, and a query matching `ownership` would find both. This extensibility is enabled by structuring your graph using a schema.
180+
181+
=== Roles give semantics
182+
183+
In a property graph, `(acme)-[:OWNS]->(globex)` relies on convention to determine which end is the parent and which is the subsidiary. In TypeDB, the roles `owner` and `subsidiary` make the semantics explicit and queryable:
184+
185+
[,typeql]
186+
----
187+
#!test[read, count=2]
188+
match
189+
$own isa ownership (subsidiary: $sub);
190+
$sub has name $name;
191+
----
192+
193+
This finds all companies that are subsidiaries of some other company, regardless of the owner.
194+
195+
You can think of roles as interfaces that let your data be interpreted from different angles - company is seen as a subsidiary, or a person is used as a director.
196+
197+
=== Attribute value identity
198+
199+
In TypeDB, attributes with the same value and type are the same instance. In other words – attributes are like their own singleton 'nodes'. If two companies share the jurisdiction `"US"`, they both own the same `jurisdiction` attribute. This provides natural deduplication and enables queries like "find all companies in the same jurisdiction" without self-joins:
200+
201+
[,typeql]
202+
----
203+
#!test[read, count=2]
204+
match
205+
$a isa company, has jurisdiction $j;
206+
$b isa company, has jurisdiction $j;
207+
not { $a is $b; };
208+
----
209+
210+
=== Relations can do more
211+
212+
The examples above use binary relations — each connecting two players — which map directly to the property graph model. But TypeDB relations can:
213+
214+
- **Own attributes** directly (like `stake-percentage` on `ownership`)
215+
- **Connect any number of participants** in a single relation with distinct roles
216+
- **Play roles in other relations** — an ownership relation can itself be reviewed, amended, or disputed
217+
218+
These last two capabilities are what make TypeDB a full hypergraph database. See the xref:{page-version}@use-cases::hypergraph.adoc[Hypergraph page] for how the companies ledger extends into acquisition deal modeling.
219+
220+
== Tradeoffs
221+
222+
TypeDB's stricter model is not always the right choice. Property graphs have advantages in several areas:
223+
224+
**Schemaless exploration.** Property graphs let you ingest data immediately and evolve structure over time. Even though TypeDB schemas are designed easily refactored, TypeDB requires some schema before any data is written. This is a strength for production systems but adds friction during early exploration.
225+
226+
**Graph algorithm ecosystems.** Neo4j's Graph Data Science library provides PageRank, community detection, shortest path, and other algorithms out of the box. TypeDB does not currently ship with graph analytics.
227+
228+
**Ecosystem size.** Property graph databases have broader tool integration (visualization, ETL, monitoring,) and larger communities.
229+
230+
== Next steps
231+
232+
* xref:{page-version}@use-cases::hypergraph.adoc[Hypergraphs] — extending the companies ledger into acquisition deal modeling
233+
* xref:{page-version}@guides::typeql/sql-vs-typeql.adoc[SQL vs TypeQL] — mapping relational database concepts to TypeDB
234+
* xref:{page-version}@home::get-started/setup.adoc[Get started] — install TypeDB and try it yourself

0 commit comments

Comments
 (0)