Gremlin 在 hasId returns 中使用 select 不正确的结果
Gremlin using select in hasId returns incorrect result
我正在尝试执行一个 gremlin 查询,其中稍后在 hasId
子句中重新使用保存的顶点 ID。我看到的是,当我输入文字 Id 时,答案是正确的,但是当我用文字替换 select('deployable_id')
时,答案是不正确的。不幸的是,在我现实生活中的例子中,我无法输入文字 ID。
我想了解为什么会出现这种行为,以及是否有更好的方法来执行此查询来避免此问题。
我正在 运行ning gremlin 对抗 AWS Neptune,但是我也可以仅使用 gremlin 控制台在本地复制这个问题。
在 gremlin 控制台中复制问题的步骤:
设置一个简单的数据集
graph = TinkerGraph.open()
g = traversal().withEmbedded(graph)
g.addV('deployable').property('name', 'd1')
g.addV('deployable').property('name', 'd2')
g.addV('library').property('name', 'l1')
g.addV('class').property('name', 'c1')
g.addV('class').property('name', 'c2')
g.addV('app').property('name', 'a1')
g.addV('app').property('name', 'a2')
g.V().has('name', 'd1').addE('ships').to(V().has('name', 'l1'))
g.V().has('name', 'd2').addE('ships').to(V().has('name', 'l1'))
g.V().has('name', 'l1').addE('includes').to(V().has('name', 'c1'))
g.V().has('name', 'l1').addE('includes').to(V().has('name', 'c2'))
g.V().has('name', 'a1').addE('deploys').to(V().has('name', 'd1'))
g.V().has('name', 'a2').addE('deploys').to(V().has('name', 'd2'))
g.V().has('name', 'a1').addE('loads').to(V().has('name', 'c1'))
g.V().has('name', 'a2').addE('loads').to(V().has('name', 'c2'))
使用此查询查找 d1 的 ID(据我所知它始终为 0)
g.V().has('name', 'd1').id()
运行字面id(即数字0)的查询
g.V().
has('name', 'd1').
as('deployable').
id().as('deployable_id').
select('deployable').
out('ships').
project('library','total_classes', 'loaded_classes').
by('name').
by(__.out('includes').count()).
by(
__.out('includes').
where(
__.in('loads').out('deploys').hasId(0)
).count()
)
这 returns 正确的结果 loaded_classes = 1
==>[library:l1,total_classes:2,loaded_classes:1]
现在 运行 使用 select
的查询
g.V().
has('name', 'd1').
as('deployable').
id().as('deployable_id').
select('deployable').
out('ships').
project('library','total_classes', 'loaded_classes').
by('name').
by(__.out('includes').count()).
by(
__.out('includes').
where(
__.in('loads').out('deploys').hasId(__.select('deployable_id'))
).count()
)
这会产生不正确的结果,其中 loaded_classes = 0
==>[library:l1,total_classes:2,loaded_classes:0]
上面的例子确实有一个解决方案(__.in('loads').out('deploys').has('name', 'd1')
),但是这个解决方案在我的实际例子中也不起作用,而且我还无法在一个简单的例子中复制这个问题。
hasId()
没有将 Traversal
作为参数的重载。它接受它是因为签名涉及 Object
但 Object
是一个标识符,因此 hasId()
假定您的 Traversal
是要搜索的标识符。图可能应该拒绝带有有意义消息的不可接受的标识符,但 TinkerGraph 特别乐于将任何 Object
用作 T.id
,因此它允许它。
我可能会 re-write 你的查询使用某种形式 where()
:
gremlin> g.V().
......1> has('name', 'd1').
......2> as('deployable').
......3> out('ships').
......4> project('library','total_classes', 'loaded_classes').
......5> by('name').
......6> by(__.out('includes').count()).
......7> by(
......8> __.out('includes').
......9> where(
.....10> __.in('loads').out('deploys').where(eq('deployable'))
.....11> ).count()
.....12> )
==>[library:l1,total_classes:2,loaded_classes:1]
我正在尝试执行一个 gremlin 查询,其中稍后在 hasId
子句中重新使用保存的顶点 ID。我看到的是,当我输入文字 Id 时,答案是正确的,但是当我用文字替换 select('deployable_id')
时,答案是不正确的。不幸的是,在我现实生活中的例子中,我无法输入文字 ID。
我想了解为什么会出现这种行为,以及是否有更好的方法来执行此查询来避免此问题。
我正在 运行ning gremlin 对抗 AWS Neptune,但是我也可以仅使用 gremlin 控制台在本地复制这个问题。
在 gremlin 控制台中复制问题的步骤:
设置一个简单的数据集
graph = TinkerGraph.open()
g = traversal().withEmbedded(graph)
g.addV('deployable').property('name', 'd1')
g.addV('deployable').property('name', 'd2')
g.addV('library').property('name', 'l1')
g.addV('class').property('name', 'c1')
g.addV('class').property('name', 'c2')
g.addV('app').property('name', 'a1')
g.addV('app').property('name', 'a2')
g.V().has('name', 'd1').addE('ships').to(V().has('name', 'l1'))
g.V().has('name', 'd2').addE('ships').to(V().has('name', 'l1'))
g.V().has('name', 'l1').addE('includes').to(V().has('name', 'c1'))
g.V().has('name', 'l1').addE('includes').to(V().has('name', 'c2'))
g.V().has('name', 'a1').addE('deploys').to(V().has('name', 'd1'))
g.V().has('name', 'a2').addE('deploys').to(V().has('name', 'd2'))
g.V().has('name', 'a1').addE('loads').to(V().has('name', 'c1'))
g.V().has('name', 'a2').addE('loads').to(V().has('name', 'c2'))
使用此查询查找 d1 的 ID(据我所知它始终为 0)
g.V().has('name', 'd1').id()
运行字面id(即数字0)的查询
g.V().
has('name', 'd1').
as('deployable').
id().as('deployable_id').
select('deployable').
out('ships').
project('library','total_classes', 'loaded_classes').
by('name').
by(__.out('includes').count()).
by(
__.out('includes').
where(
__.in('loads').out('deploys').hasId(0)
).count()
)
这 returns 正确的结果 loaded_classes = 1
==>[library:l1,total_classes:2,loaded_classes:1]
现在 运行 使用 select
的查询g.V().
has('name', 'd1').
as('deployable').
id().as('deployable_id').
select('deployable').
out('ships').
project('library','total_classes', 'loaded_classes').
by('name').
by(__.out('includes').count()).
by(
__.out('includes').
where(
__.in('loads').out('deploys').hasId(__.select('deployable_id'))
).count()
)
这会产生不正确的结果,其中 loaded_classes = 0
==>[library:l1,total_classes:2,loaded_classes:0]
上面的例子确实有一个解决方案(__.in('loads').out('deploys').has('name', 'd1')
),但是这个解决方案在我的实际例子中也不起作用,而且我还无法在一个简单的例子中复制这个问题。
hasId()
没有将 Traversal
作为参数的重载。它接受它是因为签名涉及 Object
但 Object
是一个标识符,因此 hasId()
假定您的 Traversal
是要搜索的标识符。图可能应该拒绝带有有意义消息的不可接受的标识符,但 TinkerGraph 特别乐于将任何 Object
用作 T.id
,因此它允许它。
我可能会 re-write 你的查询使用某种形式 where()
:
gremlin> g.V().
......1> has('name', 'd1').
......2> as('deployable').
......3> out('ships').
......4> project('library','total_classes', 'loaded_classes').
......5> by('name').
......6> by(__.out('includes').count()).
......7> by(
......8> __.out('includes').
......9> where(
.....10> __.in('loads').out('deploys').where(eq('deployable'))
.....11> ).count()
.....12> )
==>[library:l1,total_classes:2,loaded_classes:1]