How to Insert a Relationship using Concept Objects


#1

Hi -

I have been working on a use-case in Python wherein i need to insert data of 2 entities(say, company and location) into Grakn KG. This data is coming in a JSON format from a UI and in Python backend i need to utilize this data for inserting the entities and their relationship(please note in Grakn schema, i have already created a relationship between the two).

I am able to insert the data for the 2 entities using Concept objects by following the example given in Grakn documentation, but i am unable to decipher how to “insert the relationship” transaction between these 2 entities using Concept Objects. OR if you could share how to “write the Insert command” in python using the data of 2 entities that were earlier inserted, that would be great!

In the Grakn documentation, here is the Insert command given:

insert_iterator = tx.query("insert $x isa person, has birth-date 2018-08-06;")

How to use Variables in Insert command? I want to use variables containing the data of the 2 entities to insert a relationship transaction in Grakn using my Python code. Please help.

insert (location: $c, located: $g) isa located-in;

#2

Hi!

If I’m following correctly, you’re trying to create a relationship (say located-in) with two existing entities (say company and country) as role players!

Using the drivers, there are actually multiple ways of achieving exactly this. I’ve written three of them out in the code below, using the Python driver. Feel free to ask for more clarification if something doesn’t quite make sense :slight_smile:

import grakn

# create a client
client = grakn.Grakn('localhost:48555')
session = client.session(keyspace='test2')

# define a schema
with session.transaction(grakn.TxType.WRITE) as tx:
    tx.query("""define                     
                company sub entity,
                    plays located;
                country sub entity,
                    plays location;        
                located-in sub relationship, 
                    relates located,
                    relates location;
            """)
    tx.commit()


# approach 0, only using `query`
with session.transaction(grakn.TxType.WRITE) as tx:
    # insert company, country
    company = tx.query("insert $x isa company;").collect_concepts()[0]
    country = tx.query("insert $x isa country;").collect_concepts()[0]

    # insert a relationship with role players directly, using ID to reference previously created entities
    tx.query("match $company id {0}; $country id {1}; insert $z (located: $company, location: $country) isa located-in;".format(company.id, country.id))
    tx.commit()


# approach 1, mixed usage of `query` and Concept API
with session.transaction(grakn.TxType.WRITE) as tx:
    company = tx.query("insert $x isa company;").collect_concepts()[0]
    country = tx.query("insert $x isa country;").collect_concepts()[0]
    located_in = tx.query("insert $x isa located-in;").collect_concepts()[0]

    # retrieve the roles that we want to assign
    located_role = tx.get_schema_concept("located")
    location_role = tx.get_schema_concept("location")

    # assign these roles in the located-in relationship
    located_in.assign(located_role, company)
    located_in.assign(location_role, country)

    tx.commit()

# approach 2, purely using Concept API
with session.transaction(grakn.TxType.WRITE) as tx:
    company_type = tx.get_schema_concept("company")
    country_type = tx.get_schema_concept("country")
    located_in_type = tx.get_schema_concept("located-in")

    # instantiate instances of company, country, located-in
    company = company_type.create()
    country = country_type.create()
    located_in = located_in_type.create()

    # retrieve the roles that we want to assign
    located_role = tx.get_schema_concept("located")
    location_role = tx.get_schema_concept("location")

    # assign these roles in the located-in relationship
    located_in.assign(located_role, company)
    located_in.assign(location_role, country)

    tx.commit()

session.close()

#3

Thanks Joshua for the response.

I got it resolved myself by going through Grakn Python Driver documentation in detail yesterday(approach2 is the one which i discovered and worked for me :slight_smile:

Still, thanks for sharing all the approaches. It would be nice if Grakn team could incorporate them in the documentation so that everyone can be benefited out of it.


#4

Putting something like this in the docs is a good idea - we’re planning on doing a major doc rewrite soon so we’ll incoporate it then. Good luck!


#5

Thanks Joshua. Looking for the updated documentation.

Can you please do a favor by explaining how to insert a “Date” record using Python driver. I tested the below set of instructions given in current documentation but it is throwing “java.time.LocalDateTime” error. Manually i am able to insert a record by using ISO8601 format for date, but i am unable to comprehend how to achieve the same using Concept Objects/Query

date = datetime.datetime(year=2018, month=8, day=6) # requires `import datetime`
birth_date = birth_date_type.create(date)     # instantiate a date with a python datetime object

Thanks.


#6

There’s an example in our tests for the python client that can be found here:

Make sure you have declared an attribute with the right type before trying to call .create(date)


#7

Hi @joshua
I am following the same process as shared in the tests. However, i am still getting the error:
"“GraknTxOperationException-The value [1538123035682] must be of datatype [java.time.LocalDateTime]”

Here is the code snippet:
with session.transaction(grakn.TxType.WRITE) as tx:
person_type = tx.get_schema_concept(“person”)
person = person_type.create() # instantiate a person

    trip_query_time_type = tx.get_schema_concept("trip-query-time") # a date type attribute
    trip_query_time = datetime.datetime.now().isoformat()  #getting an ISO8601 string
    date_time_obj = dateutil.parser.parse(trip_query_time)  #Converting string to python datetime object
    trip_query_time_attr = trip_query_time_type.create(date_time_obj) # instantiate a date with a python datetime object
     person.has(trip_query_time_attr)
     tx.commit()  # write changes to Grakn

Please share your inputs.


#8

Can you clarify what dateutil is? I tried to get it as pipenv install python-dateutil but this package doesn’t have a parser.

Why don’t you just use the trip_query_time directly rather than going through the string representation?

Like this:

trip_query_time = datetime.datetime.now()
trip_query_time_attr = trip_query_time_type.create(trip_query_time)
tx.commit()

#9

Hi @joshua

I had already tried what you suggested i.e using the trip-query-time directly but got the same error.

('Server/network error: <_Rendezvous of RPC that terminated with:\n\tstatus = StatusCode.INVALID_ARGUMENT\n\tdetails = "GraknTxOperationException-The value [1538197485504] must be of datatype [java.time.LocalDateTime]. Please check server logs for the stack trace.

By the way, the idea of going through the string representation is that in actual scenario we’ll be getting the value for this attribute in a JSON, so we are trying to use a format(ISO8601) that we can parse in Python and then make use of it in Grakn(as it accepts DateTime in ISO8601 format).


#10

Hi @joshua

As already mentioned couple of times earlier, the example mentioned in Grakn documention as well as tests related to “Date” datatype is NOT WORKING as it is throwing “java.time.LoalDateTime” error.

I researched it further and found that this is due to Grakn’s requirement of accepting only ISO8601 format.

Please find some samples:

  1. Here, i am manually inserting date into Grakn in ISO8601 format (notice the “T” here)

>>> insert $x isa person has trip-query-time 2018-09-29T05:28:53.206721;
{$x id V266400 isa person;}

  1. Now, i have removed the “T” from the date format, and it failed.
    >>> insert $x isa person has trip-query-time 2018-09-29 05:28:53.206721;
    syntax error at line 1: **
    insert $x isa person has trip-query-time 2018-09-29 05:28:53.206721;
    ** ^

    extraneous input ‘:’ expecting {’;’, ‘,’, ‘isa’, ‘isa!’, ‘sub’, ‘relates’, ‘plays’, ‘id’, ‘label’, ‘when’, ‘then’, ‘has’, ‘key’, ‘(’, ‘is-abstract’, ‘datatype’, ‘regex’, ‘!=’, ‘==’, ‘!==’, ‘>’, ‘>=’, ‘<’, ‘<=’, ‘contains’, ‘true’, ‘false’, STRING, REGEX, INTEGER, REAL, DATE, DATETIME}
    syntax error at line 1: **
    insert $x isa person has trip-query-time 2018-09-29 05:28:53.206721;
    ** ^

    extraneous input ‘:’ expecting {’;’, ‘,’, ‘isa’, ‘isa!’, ‘sub’, ‘relates’, ‘plays’, ‘id’, ‘label’, ‘when’, ‘then’, ‘has’, ‘key’, ‘(’, ‘is-abstract’, ‘datatype’, ‘regex’, ‘!=’, ‘==’, ‘!==’, ‘>’, ‘>=’, ‘<’, ‘<=’, ‘contains’, ‘true’, ‘false’, STRING, REGEX, INTEGER, REAL, DATE, DATETIME}
    >>>

As Grakn client only works in Python3, can you please share a WORKING EXAMPLE how to insert a “Date” datatype using Concept Objects.


#11

It’s strange that you’re getting so many errors with Date attributes. In our tests the exact code snipped I posted (test_set_date_value) works (Python 3.6.x and 3.7).

It would be useful to take a step back and see if you can execute the test as well. If this does fail for you, it sounds like a version mismatch. Please check the versions of Python, Grakn server, and the pip grakn package and see if they’re up to date.

Blockquote
>>> insert $x isa person has trip-query-time 2018-09-29 05:28:53.206721;

This will always fail because there’s a space that cannot be parsed by the Graql parser. You’re right that we require the T to be there in the Graql console :slight_smile: