Tinkerpop Gremlin - 如何将变量聚合到遍历独立集合中

Tinkerpop Gremlin - How to aggregate variables into traversal independant collections

我目前正在阅读图形数据从业者指南并试图解决以下问题(仅用于学习目的)。以下是书籍电影数据集的上下文,在这个例子中,它使用了一个“标签”顶点、一个“电影”顶点和一个“额定”边,它的评级 属性 值为 1- 5 .

只是为了练习,并为了扩展我对书中概念的理解,我想获取所有带有“喜剧”标签的电影并计算平均 NPS。为此,我想将所有正面 (+1) 和中性或负面 (-1) 评级汇总到一个列表中。然后我希望将这些值的总和除以该列表中的变量数量(平均值)。这就是我的尝试:

dev.withSack{[]}{it.clone()}.    // create a sack with an empty list that clones when split
V().has('Tag', 'tag_name', 'comedy').
    in('topic_tagged').as('film').    // walk to movies tagged as comedy
    inE('rated').    // walk to the rated edges
        choose(values('rating').is(gte(3.0)),
            sack(addAll).by(constant([1.0])),
            sack(addAll).by(constant([-1.0]))).    // add a value or 1 or -1 to this movies list, depending on the rating
    group().
        by(select('film').values('movie_title')).
        by(project('a', 'b').
            by(sack().unfold().sum()).    // add all values from the list
            by(sack().unfold().count()).    // Count the values in the list
            math('a / b')).
    order(local).
        by(values, desc)

最后每部电影要么是“1.0”要么是“-1.0”。

"Journey of August King The (1995)": "1.0",
"Once Upon a Time... When We Were Colored (1995)": "1.0", ...

在我的测试中,这些值似乎没有按照我的预期聚合到集合中。我尝试了各种方法,但其中 none 达到了我的预期结果。

我知道我可以通过对初始值为“0.0”的麻袋进行加减,然后除以边数来实现此结果,但我希望通过使用列表获得更有效的解决方案并避免额外遍历边缘以获得计数。

是否可以使用列表来实现我的结果?如果是,怎么做?

编辑 1:

下面更简单的代码取自 Kelvins 示例,将通过简单地使用折叠步骤来汇总每个评级:

dev.V().
    has('Tag', 'tag_name', 'comedy').
        in('topic_tagged').
        project('movie', 'result').
            by('movie_title').
            by(inE('rated').
                choose(values('rating').is(gte(3.0)),
                    constant(1.0),
                    constant(-1.0)).
                fold())    // replace fold() with mean() to calculate the mean, or do something with the collection

有点尴尬,完全忘记了折叠步骤,因为折叠和展开太常见了。想多了,我想。

您可以考虑使用 aggregate 而不是 sack 的不同方法。您还可以使用 mean 步骤来避免需要 math 步骤。由于我没有你的数据,我做了一个使用 air-routes 数据集的例子,并在你的案例中使用机场海拔而不是电影评级。

gremlin> g.V().hasLabel('airport').limit(10).values('elev')
==>1026
==>151
==>542
==>599
==>19
==>143
==>14
==>607
==>64
==>313  

使用与您类似的加权系统会产生

gremlin> g.V().hasLabel('airport').limit(10).
......1>   choose(values('elev').is(gt(500)),
......2>     constant(1),
......3>     constant(-1))
==>1
==>-1
==>1
==>1
==>-1
==>-1
==>-1
==>1
==>-1
==>-1    

这些结果可以聚合成一个批量集

gremlin> g.V().hasLabel('airport').limit(10).
......1>   choose(values('elev').is(gt(500)),
......2>     constant(1),
......3>     constant(-1)).
......4>   aggregate('x').
......5>   cap('x')
==>[1,1,1,1,-1,-1,-1,-1,-1,-1]  

从那里我们可以取平均值

gremlin> g.V().hasLabel('airport').limit(10).
......1>   choose(values('elev').is(gt(500)),
......2>     constant(1),
......3>     constant(-1)).
......4>   aggregate('x').
......5>   cap('x').
......6>   unfold().
......7>   mean()
==>-0.2    

现在,这当然是人为设计的,因为您通常不会执行 aggregate('x').cap('x').unfold().mean(),您只会单独使用 mean()。但是使用这种模式你应该能够解决你的问题。

编辑添加

再多考虑一下,您甚至可以在不需要 aggregate 的情况下编写查询 - 如下所示。我使用航线距离边缘 属性 来模拟类似于您的查询的内容。该示例仅使用一个机场以保持简单。首先只是创建分数列表...

gremlin> g.V().has('airport','code','SAF').
......1>   project('airport','mean').
......2>     by('code').
......3>     by(outE().
......4>        choose(values('dist').is(gt(350)),
......5>          constant(1),
......6>          constant(-1)).
......7>          fold())
==>[airport:SAF,mean:[1,1,1,-1]]   

最后创建平均值

gremlin> g.V().has('airport','code','SAF').
......1>   project('airport','mean').
......2>     by('code').
......3>     by(outE().
......4>        choose(values('dist').is(gt(350)),
......5>          constant(1),
......6>          constant(-1)).
......7>          mean())
==>[airport:SAF,mean:0.5]

再次编辑

如果边属性可能不存在,你可以这样做...

gremlin> g.V().has('airport','code','SAF').
......1>   project('airport','mean').
......2>     by('code').
......3>     by(outE().
......4>        coalesce(values('x'),constant(100)).
......5>        choose(identity().is(gt(350)),
......6>          constant(1),
......7>          constant(-1)).
......8>          fold())
==>[airport:SAF,mean:[-1,-1,-1,-1]]