【问题标题】:How do I update a specific edge property using Gremlin/Titan/TinkerPop3?如何使用 Gremlin/Titan/TinkerPop3 更新特定的边缘属性?
【发布时间】:2017-04-06 10:17:53
【问题描述】:

目标

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

我想做的是更新weight的值。

其他要求

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

我知道的

我有以下信息:

  • Vertex 标记为“用户”
  • 边缘标签votes_for
  • 边属性type的值(在本例中为“吃”)
  • 标记为“meal”(在本例中为“pizza”)的顶点的属性name 的值,因此也是它的Vertex

我的想法

我认为我需要执行以下操作:

  1. 从 Joey 顶点开始
  2. 找到所有标记为votes_for 且具有type“吃”的出边(最多应为1)和标记为“膳食”且具有name“披萨”的出顶点。
  3. 更新边缘的weight 值。

这是我在代码中搞砸的:

//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)会更有意义吗?

感谢您的帮助!

【问题讨论】:

    标签: titan gremlin tinkerpop3


    【解决方案1】:

    你在正确的轨道上。查看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()
    

    完整的 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

    使用多个 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。如果您在Joeypizza 之间创建多个votes_for_eat,则会引发异常。

    【讨论】:

      【解决方案2】:

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

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

      所以我将尝试用一个稍微不同的查询来回答这一点。如果新边不存在,则此查询添加一条新边,然后更新/添加 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
      

      【讨论】:

      • 太棒了,+1。这可以在一个优雅的查询中处理所有要求。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-19
      • 2014-05-20
      • 1970-01-01
      • 2018-12-06
      • 2016-12-11
      • 2019-01-03
      相关资源
      最近更新 更多