Gremlin - 如何在不明确列出属性的情况下合并顶点以组合它们的属性?
Gremlin - how do you merge vertices to combine their properties without listing the properties explicitly?
背景:我正在尝试使用 this approach、使用 gremlin (tinkerpop v3) 来实现时间序列版本化数据库。
我想获取给定身份节点(蓝色)的最新状态节点(红色)(由包含时间戳范围的 'state' 边链接),但我想 return 一个聚合对象,它包含身份节点的 id (cid) 和状态节点的所有属性,但我不想明确列出它们。
(8640000000000000 是我表示没有 'to' 日期的方式 - 即边缘是当前的 - 与显示的图像略有不同)。
我已经做到了:
:> g.V().hasLabel('product').
as('cid').
outE('state').
has('to', 8640000000000000).
inV().
as('name').
as('price').
select('cid', 'name','price').
by('cid').
by('name').
by('price')
=>{cid=1, name="Cheese", price=2.50}
=>{cid=2, name="Ham", price=5.00}
但如您所见,我必须列出 'state' 节点的属性 - 在上面的示例中,是产品的名称和价格属性。但这将适用于任何域对象,因此我不想一直列出属性。我可以在此之前进行 运行 查询以获取属性,但我认为我不需要 运行 2 次查询,并且有 2 次往返的开销。我看过 'aggregate'、'union'、'fold' 等,但似乎没有任何效果。
有什么想法吗?
===================
编辑:
根据 Daniel 的回答(这并不能完全满足我想要的 ATM),我将使用他的示例图。在'modernGraph' people-create->software。如果我 运行:
> g.V().hasLabel('person').valueMap()
==>[name:[marko], age:[29]]
==>[name:[vadas], age:[27]]
==>[name:[josh], age:[32]]
==>[name:[peter], age:[35]]
然后结果是具有属性的实体列表。我想要的是,假设一个人只能创建一个软件(尽管我们希望稍后我们会看到如何将其打开以用于创建的软件列表),以包括创建的软件 'language' 属性 进入 returned 实体得到:
> <run some query here>
==>[name:[marko], age:[29], lang:[java]]
==>[name:[vadas], age:[27], lang:[java]]
==>[name:[josh], age:[32], lang:[java]]
==>[name:[peter], age:[35], lang:[java]]
目前最好的建议如下:
> g.V().hasLabel('person').union(identity(), out("created")).valueMap().unfold().group().by {it.getKey()}.by {it.getValue()}
==>[name:[marko, lop, lop, lop, vadas, josh, ripple, peter], lang:[java, java, java, java], age:[29, 27, 32, 35]]
我希望这更清楚。如果不是请告诉我。
由于您没有提供我的示例图,我将使用 TinkerPop 的玩具图来展示它是如何完成的。
假设您要合并 marko
和 lop
:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V(1).valueMap()
==>[name:[marko],age:[29]]
gremlin> g.V(1).out("created").valueMap()
==>[name:[lop],lang:[java]]
请注意,有两个 name
属性,理论上您无法预测哪个 name
会进入您的合并结果;然而,这在您的图表中似乎不是问题。
获取两个顶点的属性:
gremlin> g.V(1).union(identity(), out("created")).valueMap()
==>[name:[marko],age:[29]]
==>[name:[lop],lang:[java]]
合并它们:
gremlin> g.V(1).union(identity(), out("created")).valueMap().
unfold().group().by(select(keys)).by(select(values))
==>[name:[lop],lang:[java],age:[29]]
更新
感谢您添加示例输出。这使得提出解决方案变得容易得多(尽管我认为您的输出包含错误;vadas 没有创建任何东西)。
gremlin> g.V().hasLabel("person").
filter(outE("created")).map(
union(valueMap(),
outE("created").limit(1).inV().valueMap("lang")).
unfold().group().by {it.getKey()}.by {it.getValue()})
==>[name:[marko], lang:[java], age:[29]]
==>[name:[josh], lang:[java], age:[32]]
==>[name:[peter], lang:[java], age:[35]]
使用 gremlin 合并边和顶点属性 java DSL:
g.V().has('User', 'id', userDbId).outE(Edges.TWEETS)
.union(__.identity().valueMap(), __.inV().valueMap())
.unfold().group().by(__.select(Column.keys)).by(__.select(Column.values))
.map(v -> converter.toTweet((Map) v.get())).toList();
背景:我正在尝试使用 this approach、使用 gremlin (tinkerpop v3) 来实现时间序列版本化数据库。
我想获取给定身份节点(蓝色)的最新状态节点(红色)(由包含时间戳范围的 'state' 边链接),但我想 return 一个聚合对象,它包含身份节点的 id (cid) 和状态节点的所有属性,但我不想明确列出它们。 (8640000000000000 是我表示没有 'to' 日期的方式 - 即边缘是当前的 - 与显示的图像略有不同)。
我已经做到了:
:> g.V().hasLabel('product').
as('cid').
outE('state').
has('to', 8640000000000000).
inV().
as('name').
as('price').
select('cid', 'name','price').
by('cid').
by('name').
by('price')
=>{cid=1, name="Cheese", price=2.50}
=>{cid=2, name="Ham", price=5.00}
但如您所见,我必须列出 'state' 节点的属性 - 在上面的示例中,是产品的名称和价格属性。但这将适用于任何域对象,因此我不想一直列出属性。我可以在此之前进行 运行 查询以获取属性,但我认为我不需要 运行 2 次查询,并且有 2 次往返的开销。我看过 'aggregate'、'union'、'fold' 等,但似乎没有任何效果。
有什么想法吗?
===================
编辑: 根据 Daniel 的回答(这并不能完全满足我想要的 ATM),我将使用他的示例图。在'modernGraph' people-create->software。如果我 运行:
> g.V().hasLabel('person').valueMap()
==>[name:[marko], age:[29]]
==>[name:[vadas], age:[27]]
==>[name:[josh], age:[32]]
==>[name:[peter], age:[35]]
然后结果是具有属性的实体列表。我想要的是,假设一个人只能创建一个软件(尽管我们希望稍后我们会看到如何将其打开以用于创建的软件列表),以包括创建的软件 'language' 属性 进入 returned 实体得到:
> <run some query here>
==>[name:[marko], age:[29], lang:[java]]
==>[name:[vadas], age:[27], lang:[java]]
==>[name:[josh], age:[32], lang:[java]]
==>[name:[peter], age:[35], lang:[java]]
目前最好的建议如下:
> g.V().hasLabel('person').union(identity(), out("created")).valueMap().unfold().group().by {it.getKey()}.by {it.getValue()}
==>[name:[marko, lop, lop, lop, vadas, josh, ripple, peter], lang:[java, java, java, java], age:[29, 27, 32, 35]]
我希望这更清楚。如果不是请告诉我。
由于您没有提供我的示例图,我将使用 TinkerPop 的玩具图来展示它是如何完成的。
假设您要合并 marko
和 lop
:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V(1).valueMap()
==>[name:[marko],age:[29]]
gremlin> g.V(1).out("created").valueMap()
==>[name:[lop],lang:[java]]
请注意,有两个 name
属性,理论上您无法预测哪个 name
会进入您的合并结果;然而,这在您的图表中似乎不是问题。
获取两个顶点的属性:
gremlin> g.V(1).union(identity(), out("created")).valueMap()
==>[name:[marko],age:[29]]
==>[name:[lop],lang:[java]]
合并它们:
gremlin> g.V(1).union(identity(), out("created")).valueMap().
unfold().group().by(select(keys)).by(select(values))
==>[name:[lop],lang:[java],age:[29]]
更新
感谢您添加示例输出。这使得提出解决方案变得容易得多(尽管我认为您的输出包含错误;vadas 没有创建任何东西)。
gremlin> g.V().hasLabel("person").
filter(outE("created")).map(
union(valueMap(),
outE("created").limit(1).inV().valueMap("lang")).
unfold().group().by {it.getKey()}.by {it.getValue()})
==>[name:[marko], lang:[java], age:[29]]
==>[name:[josh], lang:[java], age:[32]]
==>[name:[peter], lang:[java], age:[35]]
使用 gremlin 合并边和顶点属性 java DSL:
g.V().has('User', 'id', userDbId).outE(Edges.TWEETS)
.union(__.identity().valueMap(), __.inV().valueMap())
.unfold().group().by(__.select(Column.keys)).by(__.select(Column.values))
.map(v -> converter.toTweet((Map) v.get())).toList();