在 gremlin(特别是 tinkerpop)中,您如何查询然后在没有第一个查询的任何结果的情况下进行第二个查询?

In gremlin (specifically tinkerpop), how do you query and then make a second query without ANY of the results from the first query?

我正在制作人脸匹配数据库。我有一张可能与另一张脸相似的面孔列表。我正在尝试获得最相似面孔的前 10 名面孔。第一张脸应该包括所有的脸。第二张脸应该排除任何与第一张脸匹配的相似脸。

// The graph
graph = TinkerFactory.createModern()
g = graph.traversal()

g.addV('face').property('faceId','face1')
g.addV('face').property('faceId','face2')
g.addV('face').property('faceId','face3')
g.addV('face').property('faceId','face4')
g.addV('face').property('faceId','face5')
g.addV('face').property('faceId','face6')
g.addV('face').property('faceId','face7')
g.addV('face').property('faceId','face8')
g.addV('face').property('faceId','face9')

g.V().has('face','faceId','face1').as('a').V().has('face','faceId','face2').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face1').as('a').V().has('face','faceId','face3').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face1').as('a').V().has('face','faceId','face4').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face1').as('a').V().has('face','faceId','face5').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face2').as('a').V().has('face','faceId','face3').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face2').as('a').V().has('face','faceId','face4').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face5').as('a').V().has('face','faceId','face6').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face6').as('a').V().has('face','faceId','face7').as('b').addE('is similar').from('a').to('b')
g.V().has('face','faceId','face8').as('a').V().has('face','faceId','face9').as('b').addE('is similar').from('a').to('b')

这让我得到了初始列表。只有最上面的数字是对的。

:> g.V()
    .hasLabel('face')
    .as('a')
    .project('faceId','count')
    .by(select('a').values('faceId'))
    .by(bothE('is similar').otherV().id().dedup().count())
    .order()
    .by('count',desc)
    .range(0,10)

这让我明白了:

    ==>[faceId:face1,count:4]
    ==>[faceId:face2,count:3]
    ==>[faceId:face5,count:3]
    ==>[faceId:face3,count:2]
    ==>[faceId:face4,count:2]
    ==>[faceId:face6,count:2]
    ==>[faceId:face7,count:1]

我试过这个来获取额外的列表

g.V().has('face','faceId',without(V().has('face','faceId','face1').bothE('is similar').bothV().values('faceId').dedup().fold())).valueMap()

理想情况下,我想要这样的东西:

==>[faceId:face1,count:4]
==>[faceId:face6,count:1]
==>[faceId:face9,count:1]

我可以先获取 'master' 列表,然后处理第一个以获得相似的 faceId,然后再次 运行 列表以获得下一个列表,如果我需要的话。我只是不知道如何让它工作。

这有效,但我不确定如何将其合并到第一个查询的 without() 部分。

g.V().has('face','faceId',without('face1','face2','face3','face4','face5')).as('a').project('faceId','count').by(select('a').values('faceId')).by(bothE('is similar').otherV().id().dedup().count()).order().by('count',desc).range(0,10)

我不太确定这是否是您想要的,但 returns 这是您的结果。通常听起来您不想多次遍历同一个顶点,在这种情况下,您可以懒惰地 store() 这些顶点并在进行时过滤掉它们:

gremlin> g.V().hasLabel('face').
......1>   project('faceId','count').
......2>     by('faceId').
......3>     by(where(without('a')).both('is similar').
......4>        where(without('a')).
......5>        store('a').
......6>        count())
==>[faceId:face1,count:4]
==>[faceId:face9,count:1]
==>[faceId:face2,count:0]
==>[faceId:face3,count:0]
==>[faceId:face4,count:0]
==>[faceId:face5,count:0]
==>[faceId:face6,count:1]
==>[faceId:face7,count:0]
==>[faceId:face8,count:0]

根据您使用的图表,此类查询可能不是确定性的,因为 Gremlin 不假设遍历流中的项目顺序在每次执行时都相同。如果重要,您需要添加自己的 order() 步骤来强制执行。这可能最终成为一个昂贵的查询,因为它是在图上全局执行的,并且需要跟踪遍历的所有顶点。在实践中,您可能需要进一步限制遍历的路径,或者可能使用不同的算法来确定相似性。