Search code examples
titangremlintinkerpop3

How do I update a specific edge property using Gremlin/Titan/TinkerPop3?


The goal

I have a simple enough task to accomplish: Set the weight of a specific edge property. Take this scenario as an example:

Example Graph Structure

What I would like to do is update the value of weight.

Additional Requirements

  • If the edge does not exist, it should be created.
  • There may only exist at most one edge of the same type between the two nodes (i.e., there can't be multiple "votes_for" edges of type "eat" between Joey and Pizza.
  • The task should be solved using the Java API of Titan (which includes Gremlin as part of TinkerPop 3).

What I know

I have the following information:

  • The Vertex labeled "user"
  • The edge label votes_for
  • The value of the edge property type (in this case, "eat")
  • The value of the property name of the vertex labeled "meal" (in this case "pizza"), and hence also its Vertex.

What I thought of

I figured I would need to do something like the following:

  1. Start at the Joey vertex
  2. Find all outgoing edges (which should be at most 1) labeled votes_for having type "eat" and an outgoing vertex labeled "meal" having name "pizza".
  3. Update the weight value of the edge.

This is what I've messed around with in code:

//vertex is Joey in this case
g.V(vertex.id())
    .outE("votes_for")
    .has("type", "eat")
    //... how do I filter by .outV so that I can check for "pizza"?
    .property(Cardinality.single, "weight", 0.99);
    //... what do I do when the edge doesn't exist?

As commented in code there are still issues. Would explicitly specifying a Titan schema help? Are there any helper/utility methods I don't know of? Would it make more sense to have several vote_for labels instead of one label + type property, like vote_for_eat?

Thanks for any help!


Solution

  • You are on the right track. Check out the vertex steps documentation.

    Label the edge, then traverse from the edge to the vertex to check, then jump back to the edge to update the property.

    g.V(vertex.id()).
      outE("votes_for").has("type", "eat").as("e").
      inV().has("name", "pizza").
      select("e").property("weight", 0.99d).
      iterate()
    

    Full Gremlin console session:

    gremlin> Titan.version()
    ==>1.0.0
    gremlin> Gremlin.version()
    ==>3.0.1-incubating
    gremlin> graph = TitanFactory.open('inmemory'); g = graph.traversal()
    ==>graphtraversalsource[standardtitangraph[inmemory:[127.0.0.1]], standard]
    gremlin> vertex = graph.addVertex(T.label, 'user', 'given_name', 'Joey', 'family_name', 'Tribbiani')
    ==>v[4200]
    gremlin> pizza = graph.addVertex(T.label, 'meal', 'name', 'pizza')
    ==>v[4104]
    gremlin> votes = vertex.addEdge('votes_for', pizza, 'type', 'eat', 'weight', 0.8d)
    ==>e[1zh-38o-4r9-360][4200-votes_for->4104]
    gremlin> g.E(votes).valueMap(true)
    ==>[label:votes_for, weight:0.8, id:2rx-38o-4r9-360, type:eat]
    gremlin> g.V(vertex.id()).outE('votes_for').has('type','eat').as('e').inV().has('name','pizza').select('e').property('weight', 0.99d).iterate(); g.E(votes).valueMap(true)
    ==>[label:votes_for, weight:0.99, id:2rx-38o-4r9-360, type:eat]
    

    Would explicitly specifying a Titan schema help?

    If you wanted to start from the Joey node without having a reference to the vertex or its id, this would be a good use case for a Titan composite index. The traversal would start with:

    g.V().has("given_name", "Joey")
    

    Are there any helper/utility methods I don't know of?

    In addition to the TinkerPop reference documentation, there are several tutorials that you can read through:

    1. Getting Started
    2. The Gremlin Console
    3. Recipes

    Would it make more sense to have several vote_for labels instead of one label + type property, like vote_for_eat?

    Depends on what your graph model or query patterns are, but more granular labels like vote_for_eat can work out fine. You can pass multiple edge labels on the traversal step:

    g.V(vertex.id()).outE('vote_for_eat', 'vote_for_play', 'vote_for_sleep')
    

    Update

    There may only exist at most one edge of the same type between the two nodes

    You can use the Titan schema to help with this, specifically define an edge label with multiplicity ONE2ONE. An exception will be thrown if you create more than one votes_for_eat between Joey and pizza.