如何通过 TinkerPop3 中的中间节点列出与给定顶点关联的节点?
How to list the nodes associated to a given vertex through intermediate nodes in TinkerPop3?
我在 TinkerPop3 中有一个图,其中节点通过具有给定权重的边连接。
给定图中的一个节点 A,我试图遍历它以获得可以从 A 以少于 N 步到达的所有节点,并按分数对它们进行排序。这个分数是通过将路径中的每条边映射到该边的权重除以步数和总步数,最后对列表求和来计算的。
这是一个例子:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> a = g.addV('name','a').next()
==>v[0]
gremlin> b = g.addV('name','b').next()
==>v[2]
gremlin> c = g.addV('name','c').next()
==>v[4]
gremlin> d = g.addV('name','d').next()
==>v[6]
gremlin> e = g.addV('name','e').next()
==>v[8]
gremlin> a.addEdge('conn', b, 'weight', 1)
==>e[10][0-conn->2]
gremlin> a.addEdge('conn', c, 'weight', 3)
==>e[11][0-conn->4]
gremlin> b.addEdge('conn', d, 'weight', 3)
==>e[12][2-conn->6]
gremlin> d.addEdge('conn', e, 'weight', 9)
==>e[14][6-conn->8]
与 "a" 相关的节点的预期分数为:
score_n = sum_over_n(weight_n-1n / (depth_n * total_N_from_a_to_n))
score_b = w_ab / (1 * 1) = 1 / 1 = 1
score_c = w_ac / (1 * 1) = 3 / 1 = 3
score_d = (w_ab / (1 * 2)) + (w_bd / (2 * 2)) = 1/2 + 3/4 = 5/4
score_e = (w_ab / (1 * 3)) + (w_bd / (2 * 3)) + (w_de / (3 * 3)) = 1/3 + 3/6 + 9/9 = 11/6
因此,结果应该是相应的节点降序排列:
c e d b
我是 TinkerPop 和 Gremlin 的新手,我一直在尝试 repeat 和 sack 步骤的组合,但没有成功。到目前为止的计划是为每次遍历在一个 sack 中累积步骤,发出分数和节点,最后按分数排序,但我担心与该过程相关的潜在性能问题。
从 TinkerPop 开始并不是最简单的遍历。我改变的第一件事是权重的数据类型。
graph = TinkerGraph.open()
g = graph.traversal()
a = g.addV('name','a').next()
b = g.addV('name','b').next()
c = g.addV('name','c').next()
d = g.addV('name','d').next()
e = g.addV('name','e').next()
a.addEdge('conn', b, 'weight', 1f)
a.addEdge('conn', c, 'weight', 3f)
b.addEdge('conn', d, 'weight', 3f)
d.addEdge('conn', e, 'weight', 9f)
这是消除舍入错误所必需的。它也可以作为遍历的一部分来完成,但我不想添加更多的步骤,因为它已经变得足够复杂了:
gremlin> g.withSack(0).V().has("name","a").
repeat(outE("conn").as("e").values("weight").as("w").
sack(assign).by(loops()).sack(sum).by(constant(1)).sack().as("l").
select("e").inV().as("v").select("v","w","l").as("x").select("v")).emit().
select(all, "x").as("x").
count(local).as("c").select("x").
map(unfold().sack(assign).by(select("w")).
sack(div).by(select("l")).
sack(div).by(select("c")).sack().fold()).
project("score","v").by(sum(local)).by(select("x").tail(local, 1).select("v")).
order().by(select("score"), decr).select("v").values("name")
==>c
==>e
==>d
==>b
更新
以下是 TP 3.0.1 的有效遍历:
gremlin> Gremlin.version()
==>3.0.1-incubating
gremlin> g.withSack(0D).V().has("name","a").
repeat(outE("conn").as("e").values("weight").as("w").
select(all,"w").count(local).as("l").
select(last,"e").inV().as("v").select(last,"v","w","l").as("x").select("v")).emit().
select(all,"x").as("x").
count(local).as("c").select(last,"x").
map(unfold().as("m").select("w").sack(sum).
select(last,"m").select("l").sack(div).
select(last,"m").select("c").sack(div).sack().fold()).as("score").
select(last, "score","x").by(sum(local)).by(tail(local, 1).select("v")).
order().by(select("score"), decr).select("x").values("name")
==>c
==>e
==>d
==>b
这种遍历的唯一好处是,weight
属性不必具有其他数据类型 - int
工作正常。
我在 TinkerPop3 中有一个图,其中节点通过具有给定权重的边连接。
给定图中的一个节点 A,我试图遍历它以获得可以从 A 以少于 N 步到达的所有节点,并按分数对它们进行排序。这个分数是通过将路径中的每条边映射到该边的权重除以步数和总步数,最后对列表求和来计算的。
这是一个例子:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> a = g.addV('name','a').next()
==>v[0]
gremlin> b = g.addV('name','b').next()
==>v[2]
gremlin> c = g.addV('name','c').next()
==>v[4]
gremlin> d = g.addV('name','d').next()
==>v[6]
gremlin> e = g.addV('name','e').next()
==>v[8]
gremlin> a.addEdge('conn', b, 'weight', 1)
==>e[10][0-conn->2]
gremlin> a.addEdge('conn', c, 'weight', 3)
==>e[11][0-conn->4]
gremlin> b.addEdge('conn', d, 'weight', 3)
==>e[12][2-conn->6]
gremlin> d.addEdge('conn', e, 'weight', 9)
==>e[14][6-conn->8]
与 "a" 相关的节点的预期分数为:
score_n = sum_over_n(weight_n-1n / (depth_n * total_N_from_a_to_n))
score_b = w_ab / (1 * 1) = 1 / 1 = 1
score_c = w_ac / (1 * 1) = 3 / 1 = 3
score_d = (w_ab / (1 * 2)) + (w_bd / (2 * 2)) = 1/2 + 3/4 = 5/4
score_e = (w_ab / (1 * 3)) + (w_bd / (2 * 3)) + (w_de / (3 * 3)) = 1/3 + 3/6 + 9/9 = 11/6
因此,结果应该是相应的节点降序排列:
c e d b
我是 TinkerPop 和 Gremlin 的新手,我一直在尝试 repeat 和 sack 步骤的组合,但没有成功。到目前为止的计划是为每次遍历在一个 sack 中累积步骤,发出分数和节点,最后按分数排序,但我担心与该过程相关的潜在性能问题。
从 TinkerPop 开始并不是最简单的遍历。我改变的第一件事是权重的数据类型。
graph = TinkerGraph.open()
g = graph.traversal()
a = g.addV('name','a').next()
b = g.addV('name','b').next()
c = g.addV('name','c').next()
d = g.addV('name','d').next()
e = g.addV('name','e').next()
a.addEdge('conn', b, 'weight', 1f)
a.addEdge('conn', c, 'weight', 3f)
b.addEdge('conn', d, 'weight', 3f)
d.addEdge('conn', e, 'weight', 9f)
这是消除舍入错误所必需的。它也可以作为遍历的一部分来完成,但我不想添加更多的步骤,因为它已经变得足够复杂了:
gremlin> g.withSack(0).V().has("name","a").
repeat(outE("conn").as("e").values("weight").as("w").
sack(assign).by(loops()).sack(sum).by(constant(1)).sack().as("l").
select("e").inV().as("v").select("v","w","l").as("x").select("v")).emit().
select(all, "x").as("x").
count(local).as("c").select("x").
map(unfold().sack(assign).by(select("w")).
sack(div).by(select("l")).
sack(div).by(select("c")).sack().fold()).
project("score","v").by(sum(local)).by(select("x").tail(local, 1).select("v")).
order().by(select("score"), decr).select("v").values("name")
==>c
==>e
==>d
==>b
更新
以下是 TP 3.0.1 的有效遍历:
gremlin> Gremlin.version()
==>3.0.1-incubating
gremlin> g.withSack(0D).V().has("name","a").
repeat(outE("conn").as("e").values("weight").as("w").
select(all,"w").count(local).as("l").
select(last,"e").inV().as("v").select(last,"v","w","l").as("x").select("v")).emit().
select(all,"x").as("x").
count(local).as("c").select(last,"x").
map(unfold().as("m").select("w").sack(sum).
select(last,"m").select("l").sack(div).
select(last,"m").select("c").sack(div).sack().fold()).as("score").
select(last, "score","x").by(sum(local)).by(tail(local, 1).select("v")).
order().by(select("score"), decr).select("x").values("name")
==>c
==>e
==>d
==>b
这种遍历的唯一好处是,weight
属性不必具有其他数据类型 - int
工作正常。