【问题标题】:Is there way to merge outgoing Vertices of two known Vertices by their ID有没有办法通过他们的ID合并两个已知顶点的传出顶点
【发布时间】:2019-01-09 01:10:22
【问题描述】:

总的来说,我是 Graph DBs 的新手,正在尝试学习 Gremlin QL。我想知道是否有一种方法可以直接合并两个已知 id 的顶点的两个直接邻居。例如,在下图中

我不想遍历整个图,我只想让两个子图根据它们的共同邻居进行合并,并根据通向同一个顶点的两条边的权重之和进行排序。

在上图中,当我使用顶点1 and 2 进行查询时,我希望能够显示顶点A, B, C, D。我希望能够合并顶点1和顶点2的outE,聚合(edge 1 -> A and Edge 2 -> A),(edge 1 -> B and Edge 2 -> B),(edge 1 -> C and Edge 2 -> C) and (edge 1 -> D and Edge 2 -> D) 并根据这个组合得分对结果进行排序。

图表创建代码如下

g.addV().property('id',1).property("type","A").as('1')
  addV().property('id',2).property("type","B").as('2').
  addV().property('id',A).property("type","X").as('A').
  addV().property('id',B).property("type","X").as('B').
  addV().property('id',C).property("type","X").as('C').
  addV().property('id',D).property("type","X").as('D').
  addE('connects').from('1').to('A').property("weight",0.1d)
  addE('connects').from('1').to('B').property("weight",0.4d)
  addE('connects').from('1').to('C').property("weight",0.2d)
  addE('connects').from('1').to('D').property("weight",0.7d)
  addE('connects').from('2').to('A').property("weight",0.5d)
  addE('connects').from('2').to('B').property("weight",0.2d)
  addE('connects').from('2').to('C').property("weight",0.7d)
  addE('connects').from('2').to('D').property("weight",0.4d).iterate()

如果我用 SQL 来表示上述数据,示例模型如下所示

create table items(id varchar(20), toId varchar(20), weight double(5,4), primary key (id, toId);

insert into items values("1","A",0.1);
insert into items values("1","B",0.4);
insert into items values("1","C",0.2);
insert into items values("1","D",0.7);
insert into items values("2","A",0.5);
insert into items values("2","B",0.2);
insert into items values("2","C",0.7);
insert into items values("2","D",0.4);

select toId, a.weight+b.weight as weight from items a, items b where a.id = "1" and b.id = "2" and a.toId = b.toId order by weight desc;

这通常返回

D, 0.11
C, 0.9
B, 0.6
A, 0.5

非常感谢您对此提供的任何帮助。

【问题讨论】:

标签: gremlin


【解决方案1】:

我对您的数据创建脚本进行了一些调整,因为它有一些语法错误:

g.addV().property('id',1).property("type","A").as('1').
  addV().property('id',2).property("type","B").as('2').
  addV().property('id','A').property("type","X").as('A').
  addV().property('id','B').property("type","X").as('B').
  addV().property('id','C').property("type","X").as('C').
  addV().property('id','D').property("type","X").as('D').
  addE('connects').from('1').to('A').property("weight",0.1d).
  addE('connects').from('1').to('B').property("weight",0.4d).
  addE('connects').from('1').to('C').property("weight",0.2d).
  addE('connects').from('1').to('D').property("weight",0.7d).
  addE('connects').from('2').to('A').property("weight",0.1d).
  addE('connects').from('2').to('B').property("weight",0.4d).
  addE('connects').from('2').to('C').property("weight",0.2d).
  addE('connects').from('2').to('D').property("weight",0.7d).iterate()

可能还有其他一些方法可以做到这一点,但在我编写查询的方法中,我决定从收集“1”和“2”两个起始顶点之间所需的边开始:

gremlin> g.V().has('id',1).
......1>   outE('connects').as('1e').
......2>   inV().as('v').
......3>   inE('connects').as('2e').
......4>   where(outV().has('id',2)).
......5>   select('1e','v','2e')
==>[1e:e[18][0-connects->6],v:v[6],2e:e[22][3-connects->6]]
==>[1e:e[19][0-connects->9],v:v[9],2e:e[23][3-connects->9]]
==>[1e:e[20][0-connects->12],v:v[12],2e:e[24][3-connects->12]]
==>[1e:e[21][0-connects->15],v:v[15],2e:e[25][3-connects->15]]

所以上面给出了我们所有的共享边,以及我们想要对其权重求和的顶点。您可以使用group() 步骤进行求和:

gremlin> g.V().has('id',1).
......1>   outE('connects').as('1e').
......2>   inV().as('v').
......3>   inE('connects').as('2e').
......4>   where(outV().has('id',2)).
......5>   select('1e','v','2e').
......6>   group().
......7>     by(select('v').by('id')).
......8>     by(select(values).
......9>        unfold().has('weight').
.....10>        values('weight').sum())
==>[A:0.2,B:0.8,C:0.4,D:1.4]

第一个by() 调制器从传入的Map 结果中获取“v”键,并从其中的顶点中提取“id”属性。第二个by() 调制器通过做一些可能不会立即清楚的事情来产生总和。它从传入的Map(即顶点和相关边)中获取值,然后只找到边缘属性为“weight”的元素(顶点将被过滤掉)。最后,它将这些权重值相加。

这部分 Gremlin 可能对您的示例中的数据进行了过多调整。如果图形结构创建的不仅仅是这些简单路径,我想您会在输出中看到一些边缘重复。如果您不关心重复并且想要总结所有内容,那么我想我所拥有的将按原样工作。如果您只想计算总和中的唯一边权重,那么您可能需要在 has('weight') 之后添加一个 dedup() 步骤。

如果您需要对结果进行排序,则可以在Map 结果中添加order() 步骤并按values 排序:

gremlin> g.V().has('id',1).
......1>   outE('connects').as('1e').
......2>   inV().as('v').
......3>   inE('connects').as('2e').
......4>   where(outV().has('id',2)).
......5>   select('1e','v','2e').
......6>   group().
......7>     by(select('v').by('id')).
......8>     by(select(values).
......9>        unfold().has('weight').
.....10>        values('weight').sum()).
.....11>   order(local).by(values, desc)
==>[D:1.4,B:0.8,C:0.4,A:0.2]

请注意,您使用local 是因为您在遍历流的当前Map 内进行排序,而不是对流本身进行排序。

【讨论】:

  • 如何根据权重总和对结果进行降序排序?
  • 当我尝试这个 g.V().has('id',1) 时出现错误。 ......1> outE('connects').as('1e')。 ......2> inV().as('v')。 ......3> inE('connects').as('2e')。 ......4> where(outV().has('id',2))。 ......5>选择('1e','v','2e')。 ......6> 组()。 ......7> by(select('v').by('id'))。 ......8> by(select(values).......9>展开().has('weight').......10> values('weight').sum( ).as('sum'))。 .....11> 订单()。 .....12> by(select('sum')) 提供的遍历器没有映射到值:{...}->[SelectOneStep(last,sum)]
  • 更新了答案以包括排序。我无法真正阅读您在评论中粘贴的有关错误的内容,但我想这与您在order() 的尝试有关。在修改后的答案中查看我上面的方法
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 2020-06-17
相关资源
最近更新 更多