gremlin 是否提供克隆顶点的能力,例如
v1->v2, v1->v3, v1->v4
,我如何简单有效地创建一个新顶点v5
,该顶点也具有指向v2, v3, v4
(边缘指向的相同位置v1's
)的边,而无需显式设置它们,而是说类似g.createV(v1).clone(v2)
.
请注意,我使用的是 AWS Neptune 版本的 gremlin,解决方案必须与之兼容。
gremlin 是否提供克隆顶点的能力,例如
v1->v2, v1->v3, v1->v4
,我如何简单有效地创建一个新顶点v5
,该顶点也具有指向v2, v3, v4
(边缘指向的相同位置v1's
)的边,而无需显式设置它们,而是说类似g.createV(v1).clone(v2)
.
请注意,我使用的是 AWS Neptune 版本的 gremlin,解决方案必须与之兼容。
clone
步骤不存在(尚),但可以通过单个查询来解决。
让我们从一些示例数据开始:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V(4).valueMap(true) // the vertex to be cloned
==>[label:person,name:[josh],age:[32],id:4]
gremlin> g.V(4).outE().map(union(identity(), valueMap()).fold()) // all out-edges
==>[e[10][4-created->5],[weight:1.0]]
==>[e[11][4-created->3],[weight:0.4]]
gremlin> g.V(4).inE().map(union(identity(), valueMap()).fold()) // all in-edges
==>[e[8][1-knows->4],[weight:1.0]]
现在,克隆顶点的查询乍一看可能有点吓人,但它实际上只是一遍又一遍的相同模式 - 在原始和克隆之间跳转以复制属性:
g.V(4).as('source').
addV().
property(label, select('source').label()).as('clone').
sideEffect( // copy vertex properties
select('source').properties().as('p').
select('clone').
property(select('p').key(), select('p').value())).
sideEffect( // copy out-edges
select('source').outE().as('e').
select('clone').
addE(select('e').label()).as('eclone').
to(select('e').inV()).
select('e').properties().as('p'). // copy out-edge properties
select('eclone').
property(select('p').key(), select('p').value())).
sideEffect( // copy in-edges
select('source').inE().as('e').
select('clone').
addE(select('e').label()).as('eclone').
from(select('e').outV()).
select('e').properties().as('p'). // copy in-edge properties
select('eclone').
property(select('p').key(), select('p').value()))
在行动中,它看起来像这样:
gremlin> g.V(4).as('source').
......1> addV().
......2> property(label, select('source').label()).as('clone').
......3> sideEffect(
......4> select('source').properties().as('p').
......5> select('clone').
......6> property(select('p').key(), select('p').value())).
......7> sideEffect(
......8> select('source').outE().as('e').
......9> select('clone').
.....10> addE(select('e').label()).as('eclone').
.....11> to(select('e').inV()).
.....12> select('e').properties().as('p').
.....13> select('eclone').
.....14> property(select('p').key(), select('p').value())).
.....15> sideEffect(
.....16> select('source').inE().as('e').
.....17> select('clone').
.....18> addE(select('e').label()).as('eclone').
.....19> from(select('e').outV()).
.....20> select('e').properties().as('p').
.....21> select('eclone').
.....22> property(select('p').key(), select('p').value()))
==>v[13]
gremlin> g.V(13).valueMap(true) // the cloned vertex
==>[label:person,name:[josh],age:[32],id:13]
gremlin> g.V(13).outE().map(union(identity(), valueMap()).fold()) // all cloned out-edges
==>[e[16][13-created->5],[weight:1.0]]
==>[e[17][13-created->3],[weight:0.4]]
gremlin> g.V(13).inE().map(union(identity(), valueMap()).fold()) // all cloned in-edges
==>[e[18][1-knows->13],[weight:1.0]]
更新
分页支持有点棘手。让我把整个事情分成三个步骤。我将使用边 ID 作为排序标准并识别最后处理的边(这在 Neptune 中可能不起作用,但您可以使用唯一的可排序属性)。
// clone the vertex with its properties
clone = g.V(4).as('source').
addV().
property(label, select('source').label()).as('clone').
sideEffect(
select('source').properties().as('p').
select('clone').
property(select('p').key(), select('p').value())).next()
// clone out-edges
pageSize = 1
lastId = -1
while (true) {
t = g.V(4).as('source').
outE().hasId(gt(lastId)).
order().by(id).limit(pageSize).as('e').
group('x').
by(constant('lastId')).
by(id()).
V(clone).
addE(select('e').label()).as('eclone').
to(select('e').inV()).
sideEffect(
select('e').properties().as('p').
select('eclone').
property(select('p').key(), select('p').value())).
count()
if (t.next() != pageSize)
break
lastId = t.getSideEffects().get('x').get('lastId')
}
// clone in-edges
lastId = -1
while (true) {
t = g.V(4).as('source').
inE().hasId(gt(lastId)).
order().by(id).limit(pageSize).as('e').
group('x').
by(constant('lastId')).
by(id()).
V(clone).
addE(select('e').label()).as('eclone').
from(select('e').inV()).
sideEffect(
select('e').properties().as('p').
select('eclone').
property(select('p').key(), select('p').value())).
count()
if (t.next() != pageSize)
break
lastId = t.getSideEffects().get('x').get('lastId')
}
我不知道 Neptune 是否允许您执行完整的脚本 - 如果没有,您需要在应用程序代码中执行外部 while 循环。