【问题标题】:How can I insert a vertex between two currently connected vertexes?如何在两个当前连接的顶点之间插入一个顶点?
【发布时间】:2017-02-20 14:12:39
【问题描述】:

我正在尝试与 Gremlin 交手。彻底阅读了文档后,我似乎仍然在概念上苦苦挣扎。

我正在按照 Neo4j 文档中的模型创建一个基本的新闻源:

http://neo4j.com/docs/snapshot/cypher-cookbook-newsfeed.html

我实际上在使用 titandb,但我遵循与上图相同的原则/模式。

到目前为止,我已经创建了一个 user 顶点图,这些顶点通过 friend 边连接。

我可以添加一个新的post 顶点并通过posted 边缘将其连接到user 顶点,如下所示:

 def activity = graph.addVertex(T.label, "post");
 activity.property("post_id", post_id);
 activity.property("time", time);
 activity.property("body", body);

 def g = graph.traversal();
 def user = g.V().hasLabel("user").has("userid", userid).next();
 user.addEdge("posted", activity, "time", time);

但是,我需要能够在单个 Gremlin 脚本中执行以下操作:

  1. 创建新的post 顶点,如上。
  2. 删除user 和任何当前连接的post 顶点之间的旧posted 边。但仅当当前存在帖子。
  3. 使用新的posted 边将新的post 顶点附加到user
  4. 最后,如果有之前的post 顶点,则通过next 边将其附加到新添加的post 顶点。最终为每个用户创建长信息流。

我一直在玩,反复试验,现在似乎有几个小时了,我似乎无法理解它。

任何帮助将不胜感激。

【问题讨论】:

    标签: titan gremlin tinkerpop tinkerpop3


    【解决方案1】:

    另一种方式(使用单次遍历):

    使用单个用户创建初始图表:

    gremlin> g = TinkerGraph.open().traversal()
    ==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
    gremlin> g.addV("user").property("userid", 123)
    ==>v[0]
    

    添加第一个帖子:

    gremlin> g.V().has("user", "userid", 123).as("user").      /* find the user                            */
               addV("post").as("p").property("post_id", 1).    /* add a new post                           */
                 property("time", System.currentTimeMillis()).
                 property("body", "bla bla").
               addE("posted").from("user").as("e").            /* connect user and post                    */
                 property("time", System.currentTimeMillis()).
               outV().                                         /* traverse to user                         */
               outE("posted").where(neq("e")).as("o").         /* traverse to any pre-existing posted edge */
               inV().                                          /* traverse to pre-existing post            */
               addE("next").to("p").                           /* connect it with the new post             */
               select("o").drop()                              /* drop the old posted edge                 */
    
    gremlin> // check
    gremlin> g.V().not(inE()).repeat(union(outE("posted").inV(), inE("next").outV())).until(__.not(union(outE("posted"), inE("next")))).path().by(label)
    ==>[user, posted, post]
    

    添加另一个帖子(相同的查询):

    gremlin> g.V().has("user", "userid", 123).as("user").
               addV("post").as("p").property("post_id", 1).
                 property("time", System.currentTimeMillis()).
                 property("body", "bla bla").
               addE("posted").from("user").as("e").
                 property("time", System.currentTimeMillis()).
               outV().
               outE("posted").where(neq("e")).as("o").
               inV().
               addE("next").to("p").
               select("o").drop()
    
    gremlin> // check
    gremlin> g.V().not(inE()).repeat(union(outE("posted").inV(), inE("next").outV())).until(__.not(union(outE("posted"), inE("next")))).path().by(label)
    ==>[user, posted, post, next, post]
    

    【讨论】:

      【解决方案2】:

      你可以这样做:

      gremlin> graph = TinkerGraph.open()
      ==>tinkergraph[vertices:0 edges:0]
      gremlin> g = graph.traversal()
      ==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
      gremlin> createPost = { user, post -> 
      ......1>   u = g.V().has('userId', user).next()
      ......2>   previous = g.V(u).outE('posted').inV().tryNext().orElse(null)
      ......3>   g.V(u).outE('posted').drop().iterate()
      ......4>   activity = graph.addVertex(T.label, "post", "postId", post)
      ......5>   u.addEdge("posted", activity)  
      ......6> 
      ......6>   if (null != previous) previous.addEdge('next', activity)
      ......7> 
      ......7>   // with titan you would want to commit the transaction
      ......8>   // graph.tx().commit()
      ......9> }
      ==>groovysh_evaluate$_run_closure1@522b2631
      

      然后添加一个用户,调用createPost()函数几次:

      gremlin> user = g.addV(label,"user", "userId", "me").next()
      ==>v[0]
      gremlin> createPost("me",1)
      gremlin> createPost("me",2)
      ==>e[8][2-next->5]
      gremlin> createPost("me",3)
      ==>e[12][5-next->9]
      gremlin> createPost("me",4)
      ==>e[16][9-next->13]
      gremlin> createPost("me",5)
      ==>e[20][13-next->17]
      

      您可以看到针对最新“post”顶点的“posted”边:

      gremlin> g.V().has('userId','me').outE()
      ==>e[19][0-posted->17]
      

      如果我们沿着传入的“下一个”边缘从那里遍历,您可以到达上一篇文章:

      gremlin> g.V().has('userId','me').out('posted').in('next')
      ==>v[13]
      

      以下显示了之前的三个帖子:

      gremlin> g.V().has('userId','me').out('posted').in('next').in('next')
      ==>v[9]
      

      你也可以沿着next穿越到任意深度:

      gremlin> g.V().has('userId','me').
                     out('posted').
                     repeat(__.in('next')).
                       until(inE().count().is(0)).emit().
                     path().
                       by(choose(label().is('post'),
                            values('postId'),
                            values('userId')))
      ==>[me,5,4]
      ==>[me,5,4,3]
      ==>[me,5,4,3,2]
      ==>[me,5,4,3,2,1]
      

      【讨论】:

      • 一个很棒的答案,谢谢。这带来了不可估量的帮助。
      • 然而,我已经接受了 Daniels 的回答,因为他的示例在一次遍历中就做到了。根据我有限的理解,这应该不是最好的吗?无论如何,您的回答确实帮助我理解了几个关键概念。非常感谢。
      • 我故意没有为了让你了解关键概念而进行一次遍历 - 所以至少那个任务已经完成:)
      猜你喜欢
      • 2015-10-19
      • 2021-10-16
      • 1970-01-01
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多