【问题标题】:How to query for multiple vertices and counts of their relationships in Gremlin/Tinkerpop 3?如何在 Gremlin/Tinkerpop 3 中查询多个顶点及其关系计数?
【发布时间】:2015-06-02 03:25:10
【问题描述】:

我正在使用 Gremlin/Tinkerpop 3 来查询存储在 TitanDB 中的图形。

该图包含具有属性的用户顶点,例如“描述”,以及表示用户之间关系的边。

我想使用 Gremlin 来获取 1) 用户的属性和 2) 与其他用户(例如,id = 123)的关系数量(在这种情况下为任何类型)。为了实现这一点,我使用了 Gremlin 3 中的 match 操作,如下所示:

g.V().match('user',__.as('user').has('description',new P(CONTAINS,'developer')),
__.as('user').out().hasId(123).values('name').groupCount('a').cap('a').as('relationships'))
.select()

此查询工作正常,除非返回多个用户顶点,例如,因为多个用户的描述中包含“开发者”一词。在这种情况下,关系计数是所有返回用户与 id 为 123 的用户之间的所有关系的总和,而不是根据需要,每个返回用户的单独计数。

是我做错了什么还是这可能是一个错误?

PS:这个问题与我前段时间在 Tinkerpop 2 中发布的一个类似查询有关,在那里我遇到了另一个问题:How to select optional graph structures with Gremlin?

【问题讨论】:

    标签: graph-databases titan gremlin


    【解决方案1】:

    这是我使用的示例数据:

    graph = TinkerGraph.open()
    g = graph.traversal()
    v123=graph.addVertex(id,123,"description","developer","name","bob")
    v124=graph.addVertex(id,124,"description","developer","name","bill")
    v125=graph.addVertex(id,125,"description","developer","name","brandy")
    v126=graph.addVertex(id,126,"description","developer","name","beatrice")
    v124.addEdge('follows',v125)
    v124.addEdge('follows',v123)
    v124.addEdge('likes',v126)
    v125.addEdge('follows',v123)
    v125.addEdge('likes',v123)
    v126.addEdge('follows',v123)
    v126.addEdge('follows',v124)
    

    我的第一个想法是:“我们真的需要match step”吗?其次,当然,我想以 TP3 方式编写它,而不是使用 lambda/closure。我在第一次迭代中尝试了各种方法,我得到的最接近的是来自 Daniel Kuppitz 的这样的东西:

    gremlin> g.V().as('user').local(out().hasId(123).values('name')
                  .groupCount()).as('relationships').select()
    ==>[relationships:[:]]
    ==>[relationships:[bob:1]]
    ==>[relationships:[bob:2]]
    ==>[relationships:[bob:1]]
    

    所以这里我们使用local 步骤将local 内的遍历限制为当前元素。这可行,但我们丢失了select 中的“用户”标签。为什么? groupCountReducingBarrierStep,在这些步骤之后路径会丢失。

    好吧,让我们回到match。我想我可以尝试使用local 进行match 步进遍历:

    gremlin> g.V().match('user',__.as('user').has('description','developer'),
    gremlin>             __.as('user').local(out().hasId(123).values('name').groupCount()).as('relationships')).select()
    ==>[relationships:[:], user:v[123]]
    ==>[relationships:[bob:1], user:v[124]]
    ==>[relationships:[bob:2], user:v[125]]
    ==>[relationships:[bob:1], user:v[126]]
    

    好的 - 成功 - 这就是我们想要的:没有 lambda 和本地计数。但是,它仍然让我觉得:“我们真的需要匹配步骤吗”?那时,Kuppitz 先生结束了最终答案,该答案大量使用了by 步骤:

    gremlin> g.V().has('description','developer').as("user","relationships").select().by()
                  .by(out().hasId(123).values("name").groupCount())
    ==>[user:v[123], relationships:[:]]
    ==>[user:v[124], relationships:[bob:1]]
    ==>[user:v[125], relationships:[bob:2]]
    ==>[user:v[126], relationships:[bob:1]]
    

    如您所见,by 可以链接(在某些步骤上)。第一个by 按顶点分组,第二个by 使用“本地”groupCount 处理分组元素。

    【讨论】:

    • 感谢您(也)回答这个问题!我决定将matchlocal 结合起来,这正是我想要的。
    • 虽然输出是等效的 - 我不清楚的一件事是 match 和多重 by 方法之间的性能差异。我想您应该对其进行测试,以至少确保它们具有可比性。如果您进行比较,请考虑在您的发现中发表评论。
    • 好的,我会的。我个人认为match 有一些论据: 1) 我发现它的声明性质很容易掌握(我之前使用过 SPARQL)——我告诉图表我想要什么,而不是如何表现。 2) match 非常适合以编程方式创建查询(例如,我结合了许多约束,如描述之一)。 3)据我了解,匹配允许查询优化。这不应该对性能有好处吗?
    • 在我的数据中,我反复执行以下查询:g.V().match('user',__.as('user').has('type','user'),__.as('user').out('written').has('name','Paper A'),__.as('user').local(__().out('knows').in('knows').or(hasId(319528),hasId(41377928)).values('name').groupCount()).as('foaf')).select() ...和:g.V().and(has('type','user'),out('written').has('name','Paper A')).as('user','foaf').select().by().by(out('knows').in('knows').or(hasId(319528),hasId(41377928)).values('name').groupCount()) 平均查询时间:match = ~4.5 秒,by = ~5.2 秒。就我而言,match 更快。
    • 是的,它允许查询优化,我并不是要让它听起来好像我对它没有信心。我只是没有看到它在使用中足以说明它何时会更快/更好/等于其他查询选项。如果你来自 SPARQL - 我明白你为什么喜欢它。我是从小精灵出生的,所以它对我来说立刻看起来很陌生。 :)
    猜你喜欢
    • 2020-03-18
    • 1970-01-01
    • 2018-03-22
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    相关资源
    最近更新 更多