如何使用Gremlin / Titan / TinkerPop3更新特定的边缘属性?

时间:2016-11-22 16:27:47

标签: titan gremlin tinkerpop3

目标

我有一个足够简单的任务来完成:设置特定边缘属性的权重。以此场景为例:

Example Graph Structure

我想要做的是更新weight的价值。

附加要求

  • 如果边缘不存在,则应创建它。
  • 在两个节点之间可能最多只存在相同类型的一个边缘(即,可以是多个" votes_for" type的边缘"吃& #34; Joey和Pizza之间。
  • 任务应该使用Java API of Titan(包括Gremlin作为TinkerPop 3的一部分)来解决。

我所知道的

我有以下信息:

  • Vertex标记为"用户"
  • 边缘标签votes_for
  • 边缘属性type的值(在这种情况下,"吃")
  • 标有" meal"的顶点的属性name的值(在这种情况下"披萨"),因此也是Vertex

我的想法

我想我需要做以下事情:

  1. 从Joey顶点开始
  2. 查找标有votes_for type"吃"的所有外向边(最多应为1)和一个标有"饭"拥有name"披萨"。
  3. 更新边缘的weight值。
  4. 这就是我在代码中搞砸的内容:

    //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?
    

    如代码所述,仍有问题。明确指定Titan架构会有帮助吗?有没有我不知道的帮助/实用方法?拥有多个vote_for标签而不是一个标签+ type属性更合理,例如vote_for_eat

    感谢您的帮助!

3 个答案:

答案 0 :(得分:8)

你走在正确的轨道上。查看vertex steps documentation

标记边缘,然后从边缘遍历到顶点进行检查,然后跳回边缘以更新属性。

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控制台会话:

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]

会明确指定Titan架构帮助吗?

如果您想从Joey节点开始而没有引用vertex或其id,那么对于Titan composite index来说这将是一个很好的用例。遍历将从以下开始:

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

有没有我不知道的帮助/实用方法?

除了TinkerPop reference documentation之外,您还可以阅读以下几个教程:

  1. Getting Started
  2. The Gremlin Console
  3. Recipes
  4. 拥有多个vote_for标签而不是一个标签+类型属性更合理,例如vote_for_eat?

    取决于您的图表模型或查询模式是什么,但更精细的标签如vote_for_eat可以很好地解决。您可以在遍历步骤中传递多个边缘标签:

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

    <强>更新

    两个节点之间可能只存在同一类型的最多一个边

    您可以使用Titan架构来帮助解决此问题,特别是定义edge label with multiplicity ONE2ONE。如果您在votes_for_eatJoey之间创建多个pizza,则会引发异常。

答案 1 :(得分:4)

杰森几乎已经回答了你所有的问题。缺少的唯一方面是:

  

如果边缘不存在,则应创建它。

所以我会尝试用稍微不同的查询回答这一点。如果此查询尚不存在,则会添加新边,然后更新/添加weight属性:

g.V(vertex.id()).outE('votes_for').has('type', 'eat')
    .where(__.inV().hasLabel('meal').has('name','pizza')) // filter for the edge to update
    .tryNext()                                            // select the edge if it exists
    .orElseGet({g.V(vertex.id()).next()
        .addEdge('votes_for', g.V(pizzaId).next(), 'type', 'eat')}) // otherwise, add the edge
    .property('weight', 0.99)               // finally, update / add the 'weight' property

您可以在Gremlin.Bin上看到完整示例。

答案 2 :(得分:0)

在Gremlin中,添加边的查询可用于更新边。 让Joey Tribbiani节点有id =“123”,披萨有id =“234”,更新后的重量值为0.9

g.V('123').addE('votes_for').to(g.V('234')).property('weight','0.9')

满足附加要求

  1. 如果边缘不存在,则会创建
  2. 不会发生相同边缘的复制
  3. 此外,这也将保持其他财产的完整性。