Edit on Github

An Overview

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

Let’s get started!

Run Grakn

Install Grakn and start the Grakn Server.

The Schema

A Grakn schema is the blueprint of a Grakn 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.

define

title sub attribute,
  datatype string;

event-date sub attribute,
  abstract,
  datatype date;
approved-date sub event-date;

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

friendship sub relation,
    relates friend,
    plays approved-friendship,
    plays listed-friendship;

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

friends-list sub relation,
    has title,
    relates list-owner,
    relates listed-friendship;

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

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

Download and Load the Complete Schema

First, download the social-network/schema.gql which contains the complete schema for the social network knowledge graph. Now, we need to load this schema into a keyspace. To do this, we use the non-interactive mode of the Grakn Console.

[Note] Feel free to study the content of `social-network-schema.gql`. 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 [Grakn Workbase](../workbase/overview).

While in the unzipped directory of the Grakn distribution, via terminal, run:

./grakn console --keyspace social_network --file path-to-the-social-network/schema.gql

Load the Dataset

Download the social-network/data.gql and load it into the same keyspace. Run:

./grakn console --keyspace social_network --file path-to-the-social-network/data.gql

As you may have guessed it, social-network-data.gql contains a series of Graql 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 Grakn Clients to migrate the dataset into the target keyspace.

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 Grakn Console, Grakn Workbase or one of the Grakn Clients.

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

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

Enter the social_network keyspace using the Console.

$ ./grakn console -k social_network

Write the query to retrieve the desired result.

match $tra (traveler: $per) isa travel; (located-travel: $tra, travel-location: $loc) isa location-of-travel; $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 friendships using Workbase

Visualise all married people

Retrieve all employments using Client Java

package grakn.examples;

import grakn.client.GraknClient;
import static graql.lang.Graql.*;
import graql.lang.query.GraqlGet;
import grakn.core.concept.answer.ConceptMap;

import java.util.List;

public class SocialNetworkQuickstartQuery extends Throwable {
    public static void main(String[] args) {
        GraknClient client = new GraknClient("localhost:48555");
        GraknClient.Session session = client.session("social_network");
        GraknClient.Transaction transaction = session.transaction().write();

        GraqlGet 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"))
        ).get();

        List<ConceptMap> answers = transaction.execute(query);

        for (ConceptMap answer : answers) {
            System.out.println(answer.get("per-fn").asAttribute().value());
            System.out.println(answer.get("org-n").asAttribute().value());
            System.out.println(" - - - - - - - - ");
        }

        transaction.close();
        session.close();
    }
}

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

from grakn.client import GraknClient

with GraknClient(uri="localhost:48555") as client:
    with client.session(keyspace = "social_network") as session:
      with session.transaction().read() as transaction:
        query = '''
          match
            $pos isa media;
            $fun isa emotion;
            $fun "funny";
            $per has gender "female";
            (reacted-emotion: $fun, reacted-to: $pos, reacted-by: $per) isa reaction;
          get $pos;
        '''
        answer_iterator = transaction.query(query)
        for answer in answer_iterator:
          print(answer.map().get("pos").id)

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

const GraknClient = require("grakn-client");

async function getAverageSalaryAt (orgName) {
    const client = new GraknClient("localhost:48555");
	const session = await client.session("social_network");
	const transaction = await session.transaction().read()
	const query = `
		match
			$org isa organisation, has name "${orgName}";
			($org, $per) isa employment, has salary $sal;
		get $sal; mean $sal;
	`
	const answerIterator = await transaction.query(query);
	const answer = await answerIterator.next();
	if (answer) {
		console.log(await answer.number());
	} else {
	  console.log(`No one works at ${orgName}`);
	}
	await transaction.close();
	await session.close();
	client.close();
}

getAverageSalaryAt("Pharos"); // asynchronous call

Insert and Delete Data

We can create and delete instances of data in a Grakn 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";
commit
[Important] Any manipulation made in the schema or the data instances, is not persisted to the original keyspace 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";
commit

Delete the newly added person

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

Store Knowledge

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

Let’s look at some simple examples of how Grakn uses rules for reasoning over explicit data.

define

course-enrollment-mutuality sub relation,
  relates coursemate,
  relates mutual-course-enrollment;

people-taken-the-same-course sub rule,
  when {
    $sce1 (student: $p1, enrolled-course: $sc) isa school-course-enrollment;
    $sce2 (student: $p2, enrolled-course: $sc) isa school-course-enrollment;
    $p1 != $p2;
  }, then {
    (coursemate: $p1, coursemate: $p2, mutual-course-enrollment: $sce1, mutual-course-enrollment: $sce2) isa course-enrollment-mutuality;
  };

As you can see in the social_network_data.gql file, no instance of course-enrollment-mutuality was ever inserted. It’s only the rule above that allows Grakn to infer this knowledge and know the answer to the following question at query time.

match
  $per isa person, has full-name "Miriam Morton";
  ($per, coursemate: $mate) isa course-enrollment-mutuality;
  $mate has full-name $mate-fn;
get $mate-fn;

Given the second rule:

define

school-mutuality sub relation,
  relates schoolmate,
  relates mutual-school;

people-gone-to-the-same-school sub rule,
  when {
    (student: $p1, enrolled-course: $c1) isa school-course-enrollment;
    (student: $p2, enrolled-course: $c2) isa school-course-enrollment;
    (offered-course: $c1, offerring-school: $s) isa school-course-offerring;
    (offered-course: $c2, offerring-school: $s) isa school-course-offerring;
    $p1 != $p2;
  }, then {
    (schoolmate: $p1, schoolmate: $p2, mutual-school: $s) isa school-mutuality;
  };

We can query for people who have attended the same school and taken the same course, like so:

match
  (coursemate: $mate-1, coursemate: $mate-2) isa course-enrollment-mutuality;
  (schoolmate: $mate-1, schoolmate: $mate-2) isa school-mutuality;
  $mate-1 has full-name $mate-1-fn;
  $mate-2 has full-name $mate-2-fn;
get $mate-1-fn, $mate-2-fn;

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 Grakn.

Distributed Analytics With Grakn

The Graql compute queries are designed to traverse the knowledge graph in parallel over a large dataset, distributed across multiple machines. We can use the compute queries to retrieve statistical information, find the shortest path between any two nodes, identify significant nodes based on their centrality and identify clusters within the knowledge graph.

Let’s look at a few examples of running compute on the genealogy knowledge graph.

Retrieve the mean of an attribute owned by a given type

compute mean of salary, in employment;

Retrieve the total number of instances of a given type

compute count in travel;

Find the shortest path between two instances

match $x has full-name "Dominic Lyons"; $y has full-name "Haider Johnson"; get;
{$x id V446496 isa person; $y id V229424 isa person;}
compute path from V446496, to V229424;
{V184392, V442424, V90344}

Identify clusters in a subgraph

compute cluster in [person, employment, organisation], using connected-component;
{V192656}
{V663728, V266336, V262392, V680112, V479408}
{V180272, V446496, V278672, V463024, V671920}
{V172176}
{V360448, V250104, V176176, V667824, V180368, V303200, V639152}
{V647200, V295008, V237808, V225328, V364544, V372832, V356352, V167984, V266488, V299104, V663584}
{V401584, V229424, V639008, V213040, V655392}

Where Next?