How to create an EDGE on the go?

Hi,

I have a requirement where i need to derive an edge avoiding two edges between three vertices. Below is the model.

V1: Person (Phone#)

V2: Calls(Callid, Calling_Number, Called_Number, Call_Date) // I have put this vertex in order to log multiple call made from one person to another

E1: Made_call(From Person, TO Calls)

E2: Received_Call (From Calls, TO Person)

I can traverse a contact made in two hops i.e through Made_call -> Calls and received_call -> Person

On the graph, I see three vertices representing a direct contact which looks messy.

What i want is to create a direct edge KNOWS(or whatever you call it) from PERSON to PERSON eliminating the CALLS vertex in the middle. // I should still see multiple EDGEs in case of multiple calls made from a person t another

Can anyone help me with achieving this ?

Your help is appreciated.

Thank you

Hanif

Khan,

It sounds like your current schema looks like the following:

Screen Shot 2019-06-12 at 11.18.54 AM.png

And you’re wanting to change it to the following

where you can directly get to a known contact in a single hop. Let me know if the above is correct or if you were truly wanting to simplify the existing schema to something like this

Screen Shot 2019-06-12 at 2.35.32 PM.png

If it’s the former, then something akin to the following may help you out

MapAccum<VERTEX, BagAccum<VERTEX>> @@madeCallMap;
SetAccum<VERTEX> @contactList;
SetAccum<VERTEX> @newContactList;
OrAccum @newContact = FALSE;

personList = {Person.*};

/We only care about persons who have made calls, and making use of neighbors function call from the call vertex allows us to get all contacts/
personList = SELECT p FROM personList:p-(Made_call:e)->Calls:c ACCUM @@madeCallMap += (p → c.neighbors(“Received_Call”) );

/Let’s grab a list of existing contacts, so we are not upserting every edge, we want to limit this to creating to just the new relationships/
existingContactList = SELECT p FROM personList:p-( Has_contacted:e )->Person:c ACCUM p.@contactList += c;

/Using accumulators and information from the Selects above we can trim our list of persons to just those with new contacts/
personList = SELECT p FROM personList:p
ACCUM
FOREACH contact IN @@madeCallMap.get(p) DO
IF NOT p.@contactList.contains(contact) THEN
p.@newContactList += contact,
p.@newContact += TRUE
END
END;

/For each new contact we’re going to create a new edge to make the relationship a single hop/
personList = SELECT p FROM personList:p
WHERE p.@newContact == TRUE
POST-ACCUM
FOREACH contact IN p.@newContactList DO
/This is how you can create an edge during a query, while testing it may be better to comment this out and try some print statements to make sure you’re getting the result you want first/
INSERT INTO Has_contacted (FROM, TO) VALUES( p, contact )
END;

I think that will give you what you want by allowing you to hop person to person. However please note this is acting merely as an existential relationship and the multiple edge statement in your question is what is giving me pause. If it’s the latter case of simplifying the schema, then I’m assuming the intent is to have an edge between person A and person B for every call that is made.

This is getting into an idea of edge cardinality, which to my knowledge is a feature on the TigerGraph road map that has not yet been implemented (According to this Redirecting to Google Groups). What this means is that if you have person A and person B, you can’t have multiple edges of the same type from A to B. One way to get around this is to make use of a List attribute on the edge from A to B.

However for what it’s worth I’d recommend keeping the Calls vertex as it gives more flexibility in the long term. For example with a call vertex you could easily support the concept of group calls.

Thank you Ric.

The first model is exactly the one I have currently designed. I need this CALLS vertex in the middle just to log multiple calls in between two persons. I don’t want to change the model to PERSON vertex only since it won’t allow me visualizing multiple edges. What I wanted is WHETHER I CAN PRINT THE PERSON-MADE_CALL->CALLS-RECEIVED->PERSON (i would also like to know exact syntax of this kind of traversal plz) as an EDGE like, person A - contacted -> person B, at run time through query while the model remains as it is? it is just to visualize it. I hope this makes sense.

Apologies Ric. I missed that you had provided query for the scenario. Looking at now. but i have just one confusion below. where did you derive Has_contacted from? I don’t see it anywhere in the model!

/Let’s grab a list of existing contacts, so we are not upserting every edge, we want to limit this to creating to just the new relationships/

existingContactList = SELECT p FROM personList:p-( Has_contacted:e )->Person:c ACCUM p.@contactList += c;

It would be the new edge type we are creating to provide a single hop from a person to a person. In your original question you said KNOWS, or whatever, so I just tried to use a more meaningful name. That piece of the query is to allow for subsequent reruns once you start populating instances of that new edge type. Should correspond to that second picture model

I got it now. so I need to create the has_contacted edge but not populate it so that it can be populated in the query you have provided below. One more question on below snippet.
what does the following comment mean? I am pretty much naive to TG so I would appreciate if you write how to visualize the new graph with this new edge. I don’t know how to print instead of inserting it in the EDGE.

Thank you.

personList = SELECT p FROM personList:p
WHERE p.@newContact == TRUE
POST-ACCUM
FOREACH contact IN p.@newContactList DO
/This is how you can create an edge during a query, while testing it may be better to comment this out and try some print statements to make sure you’re getting the result you want first/
INSERT INTO Has_contacted (FROM, TO) VALUES( p, contact )

            END;

Of course. So if you made the following change to the code snippet

/*Comment out this whole block that creates edges personList = SELECT p FROM personList:p WHERE p.@newContact == TRUE POST-ACCUM FOREACH contact IN p.@newContactList DO INSERT INTO Has_contacted (FROM, TO) VALUES( p, contact ) END; */ /*Instead simply add the following*/ PRINT personList;

With that “PRINT” statement I’m able to see what changes would be made without making them. The response can be voluminous , so it’s always best to use “LIMIT”. I mainly use “PRINT” to help me make sure I’m getting the results I’m expecting. If you just add the print statement at the end and keep the code the same then you can see the changes that were made for each run. So with the schema we have defined

And the following simple data set I created

Where blue vertices are Persons and pink vertices are calls. If run the original query and add that PRINT statement I get the following JSON response
[

  {

    "personList": [

      {

        "v_id": "B",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [],

          "@newContactList": [

            "C"

          ]

        }

      },

      {

        "v_id": "A",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [],

          "@newContactList": [

            "B",

            "C"

          ]

        }

      },

      {

        "v_id": "C",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [],

          "@newContactList": [

            "B",

            "A"

          ]

        }

      },

      {

        "v_id": "D",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [],

          "@newContactList": [

            "B"

          ]

        }

      },

      {

        "v_id": "E",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [],

          "@newContactList": [

            "D",

            "A"

          ]

        }

      }

    ]

  }

]

And my graph would now look like the following

If we remove an edge, say the one between Person E and Person A

Screen Shot 2019-06-13 at 9.13.24 AM.png

And we rerun the same query, our response is now just

[

  {

    "personList": [

      {

        "v_id": "E",

        "v_type": "Person",

        "attributes": {

          "PhoneNumber": "",

          "@newContact": true,

          "@contactList": [

            "D"

          ],

          "@newContactList": [

            "A"

          ]

        }

      }

    ]

  }

]

Thank you Ric. This is very helpful indeed.

Thank you so much.

-Hanif

Hi Khan,

I have one more suggestion to handle the event nodes. You can split your “Calls” vertex type into different types. For example, you can have 12 different Calls types and one type for one month. For example, “JanCalls”, “FebCalls”, .etc. While change your edge schema so that it is from person to ANY type. In this way, you can keep only most recent one year data into your database. Because tigergraph provide “delete by type” API to release data belongs to the same type.

V1: Person (Phone#)

V2: JanCalls(Callid, Calling_Number, Called_Number, Call_Date) // I have put this vertex in order to log multiple call made from one person to another

V3: FebCalls(Callid, Calling_Number, Called_Number, Call_Date) // I have put this vertex in order to log multiple call made from one person to another

V4: MarchCalls(Callid, Calling_Number, Called_Number, Call_Date) // I have put this vertex in order to log multiple call made from one person to another

E1: Made_call(From Person, TO *)

E2: Received_Call (*, TO Person)

This is our experience of handles big number of event nodes.

Best Wishes,

Dan