Edit on Github

An Overview

In this tutorial, we go through creating and interacting with a TypeDB knowledge graph representing a social network. In the process, we learn about the constructs of the TypeDB Schema, visualise the knowledge graph, perform read and write queries and explore the power of automated reasoning and analytics with TypeDB.

Let’s get started!

Run TypeDB

Install TypeDB and start the TypeDB Server.

The Schema

A TypeDB schema is the blueprint of a TypeDB knowledge graph. The code presented below is only a part of the schema for the social network knowledge graph that represents the concepts of friendship.


title sub attribute, value string;

event-date sub attribute, abstract, value datetime;
approved-date sub event-date;

## an abstract relation, only to be subtyped by other relations
request sub relation,
  owns approved-date,
  relates subject,
  relates requester,
  relates respondent;

friendship sub relation,
    relates friend,
    plays friend-request:friendship,
    plays friendship-list:listed;

## an example of subtyping in TypeDB
friend-request sub request,
    relates friendship as subject,
    relates friend-requester as requester,
    relates friend-respondent as respondent;

friendship-list sub relation,
    owns title,
    relates owner,
    relates listed;

person sub entity,
    plays friendship:friend,
    plays friend-request:friend-requester,
    plays friend-request:friend-respondent,
    plays friendship-list:owner;

The code you see above is TypeQL. TypeQL is the language for the TypeDB knowledge graph. Whether it’s through the TypeDB Console, Studio or one of the TypeDB Clients, TypeDB accepts instructions and provides answers only in its own language - TypeQL.

Download and Load the Complete Schema

First, download the social-network/schema.tql which contains the complete schema for the social network knowledge graph. Now, we need to load this schema into a database. To do this, we use the TypeDB Console.

[Note] Feel free to study the content of `social-network-schema.tql`. The definitions have been divided into multiple sections for better understandability, with each section containing the (commented-out) query for visualisation of the corresponding section in [TypeDB Studio](../studio/overview).
[Note] On write windows-style paths, you'll have to use `\\` to escape the backslash characters. With Unix-style paths you can use single forwardslash `/`.

While in the unzipped directory of the TypeDB distribution, via terminal, open the console:

./typedb console

Create a database called social_network:

> database create social_network

Open a schema write transaction:

> transaction social_network schema write

Inside that transaction, load the schema from file using the source command:

social_network::schema::write> source path-to-the-social-network/schema.tql
social_network::schema::write> commit

Load the Dataset

Download the social-network/data.tql and load it into the same database. In the already opened console, create a data write transaction to the social_network database and use the source command to load the data from file:

> transaction social_network data write
social_network::data::write> source path-to-the-social-network/data.tql
social_network::data::write> commit

As you may have guessed, social-network-data.tql contains a series of TypeQL insert queries that creates data instances in the social network knowledge graph. In a real-world application, it’s more likely that we have the data in some data formats such as CSV, JSON or XML. In such a case, we need to use one of the TypeDB Clients to migrate the dataset into the target database.

Query the Knowledge Graph

Now that we have some data in our social network knowledge graph, we can go ahead and retrieve some information from it. To do this, we can use the TypeDB Console, TypeDB Studio or one of the TypeDB Clients.

Let’s see an example of running TypeQL get queries via each of these interfaces.

Retrieve the full name of everyone who has travelled to a location using TypeDB Console

Using the open console, open a read transaction for the social_network database:

> transaction social_network data read

At the prompt, write this query to retrieve the desired results.

match $tra (traveler: $per) isa travel; (located: $tra, location: $loc) isa localisation; $loc has name "French Lick"; $per has full-name $fn; get $fn;

The result contains the following answers:

{$fn "Solomon Tran" isa full-name;}
{$fn "Julie Hutchinson" isa full-name;}
{$fn "Miriam Morton" isa full-name;}

Visualise all risky banks

[Warning] TypeDB Workbase is currently in the process of being replaced with a more performant application: TypeDB Studio, which is available as an alpha release on [github](https://github.com/vaticle/typedb-studio/releases)

Visualise all risky banks

Retrieve all employments using Client Java

package com.vaticle.doc.examples;

import com.vaticle.typedb.client.TypeDB;
import com.vaticle.typedb.client.api.TypeDBClient;
import com.vaticle.typedb.client.api.TypeDBOptions;
import com.vaticle.typedb.client.api.TypeDBSession;
import com.vaticle.typedb.client.api.TypeDBTransaction;

import static com.vaticle.typeql.lang.TypeQL.*;

import com.vaticle.typeql.lang.query.*;
import com.vaticle.typedb.client.api.answer.ConceptMap;

import java.util.stream.Stream;

import java.util.List;

public class SocialNetworkQuickstartQuery {
    public static void main(String[] args) {
        TypeDBClient client = TypeDB.coreClient("localhost:1729");
        try (TypeDBSession session = client.session("social_network", TypeDBSession.Type.DATA)) {
            TypeDBOptions options = TypeDBOptions.core().infer(true); // enable reasoning
            try (TypeDBTransaction transaction = session.transaction(TypeDBTransaction.Type.WRITE, options)) {
                TypeQLMatch query = match(
                        var().rel("employer", var("org")).rel("employee", var("per")).isa("employment"),
                        var("per").has("full-name", var("per-fn")),
                        var("org").has("name", var("org-n"))

                Stream<ConceptMap> answers = transaction.query().match(query);

                answers.forEach(answer -> {
                    System.out.println(" - - - - - - - - ");

Lazily retrieve all photos and videos that have been found funny by women using Client Python

from typedb.client import *

with TypeDB.core_client("localhost:1729") as client:
    with client.session("social_network", SessionType.DATA) as session:
      options = TypeDBOptions.core()
      options.infer = True # enable reasoning
      with session.transaction(TransactionType.READ, options) as transaction:
        query = '''
            $pos isa media;
            $fun isa emotion;
            $fun "funny";
            $per has gender "female";
            (emotion: $fun, to: $pos, by: $per) isa reaction;
          get $pos, $fun;
        answer_iterator = transaction.query().match(query)
        for answer in answer_iterator:
          print(answer.get("fun").get_value()) # get attribute value

Retrieve the average salary of all employees at Pharos using Client Node.js

const { TypeDB, SessionType, TransactionType, TypeDBOptions } = require("typedb-client");

async function getAverageSalaryAt (orgName) {
    const client = TypeDB.coreClient("localhost:1729");
	const session = await client.session("social_network", SessionType.DATA);
	const options = TypeDBOptions.core({infer: true}); // enable reasoning
	const transaction = await session.transaction(TransactionType.READ, options)
	const query = `
			$org isa organisation, has name "${orgName}";
			($org, $per) isa employment, has salary $sal;
		get $sal; mean $sal;
	const answer = await transaction.query.matchAggregate(query);
	if (answer.isNumber()) {
	} else {
	  console.log(`No one works at ${orgName}`);

	await transaction.close();
	await session.close();

getAverageSalaryAt("Pharos"); // asynchronous call

Insert and Delete Data

We can create and delete instances of data in a TypeDB knowledge graph by running insert and delete queries. Let’s give them a try using the Console.

Insert an instance of type person

insert $per isa person, has full-name "Johny Jimbly Joe", has gender "male", has email "johnyjj@gmail.com";
[Important] Any manipulation made in the schema or the data instances, is not persisted to the original database until we run the `commit` command.

Associate the newly added person with a nickname

match $per isa person, has email "johnyjj@gmail.com"; insert $per has nickname "JJJ";

Delete the newly added person

match $per isa person, has full-name "Johny Jimbly Joe"; delete $per isa person;

Store Knowledge

TypeDB is capable of reasoning over data to infer new knowledge, commonly known as automated reasoning or inference. Inference in a TypeDB knowledge graph is made via pre-defined Rules.

Let’s look at some simple examples of how TypeDB uses rules for reasoning over explicit data. Let’s say we want to find out what content a particular person has permission to view.

content-permission sub relation,
  relates grantee,
  relates content;

As you can see in the social_network_data.tql file, no instance of content-permission was ever inserted. It’s only through rules that allows TypeDB to infer this knowledge and know the answer to the following question at query time (if running in Console, make sure you start with transaction with --infer true to enable reasoning!)

$p isa person, has email "julie.hutchinson@gmail.com"; 
(grantee: $p, content: $c)isa content-permission; 
get $c;

Have a look at the social_network_data.tql file, there are a number of rules written to give permission to view content, based on how or where the content was shared.

Let’s look at another rule:


mutual-friendship sub relation,
  relates mutual-friend,
  relates one-degree-friend;

rule people-have-mutual-friends:
  when {
	($p1, $p2) isa friendship;
	($p2, $p3) isa friendship;
  } then {
	(one-degree-friend: $p1, one-degree-friend: $p3, mutual-friend: $p2) isa mutual-friendship;

We can query for people who have friends in common, like so (again with reasoning enabled):

$p isa person, has email "julie.hutchinson@gmail.com"; 
$p2 isa person, has full-name $name; 
(one-degree-friend: $p2, mutual-friend: $p)isa mutual-friendship; 
get $p2, $name;

Similar to the first rule, the answer we’re asking for here, was never injected into the knowledge graph and is being inferred at query time by TypeDB.

Where Next?