如何在两个当前连接的顶点之间插入一个顶点?

How can I insert a vertex between two currently connected vertexes?

我正在努力掌握 Gremlin。彻底阅读文档后,我似乎仍然在概念上苦苦挣扎。

我正在创建一个基本的新闻源,遵循此处 Neo4j 文档中的模型:

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

我实际上使用的是 titandb,但我遵循与上面所示相同的 principles/schema。

到目前为止,我已经创建了一个包含 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 边。但是仅当,当前存在post。
  3. 使用新的 posted 边将新的 post 顶点附加到 user
  4. 最后,如果之前有一个 post 顶点,则通过 next 边将其附加到新添加的 post 顶点。最终为每个用户创建 post 的长流。

我一直在尝试,尝试和错误,现在似乎已经好几个小时了,但似乎无法理解它。

如有任何帮助,我们将不胜感激。

您可以采用以下一种方法:

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]

可以看到 "posted" 边指向最新的 "post" 顶点:

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

如果我们从那里沿着传入的 "next" 边穿过,您可以到达前一个 post:

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

以下显示前三个 post:

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]

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

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

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

添加第一个post:

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]

添加另一个 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]