如何解决Tinkerpop Gremlin-如何将变量汇总到遍历独立的集合中
我正在阅读《 Practitioner's Graph Data指南》,并试图解决以下问题(仅出于学习目的)。以下是书籍电影数据集的上下文,在此示例中,该数据集使用了“标签”顶点,“电影”顶点和“定级”边缘,其评级属性值为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",...
在我的测试中,似乎这些值并没有像我期望的那样聚合到集合中。我尝试了各种方法,但没有一个能达到我的预期效果。
我知道我可以通过在麻袋中添加和减去初始值“ 0.0”,然后除以边数来实现此结果,但是我希望通过使用列表并避免使用更有效的解决方案再次遍历边缘以获得计数。
是否可以使用列表来达到目标?如果可以,怎么办?
编辑1:
下面的简单得多的代码取材于开尔文(Kelvins)示例,只需使用折叠步骤即可汇总每个评分:
dev.V().
has('Tag','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
步骤。由于我没有您的数据,因此我举了一个示例,该示例使用空中航线数据集,并根据您的情况使用机场海拔而非电影等级。
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)),......3> constant(-1)).
......4> aggregate('x').
......5> cap('x')
==>[1,1,-1,-1]
从那里我们可以取平均值
gremlin> g.V().hasLabel('airport').limit(10).
......1> choose(values('elev').is(gt(500)),......3> constant(-1)).
......4> aggregate('x').
......5> cap('x').
......6> unfold().
......7> mean()
==>-0.2
现在,这当然是人为设计的,因为您通常不会自己单独使用aggregate('x').cap('x').unfold().mean()
来完成mean()
。但是,使用这种模式应该可以解决您的问题。
已编辑添加
对此进行更多思考,您可能甚至不需要aggregate
即可编写查询-如下所示(如下)。我使用了航空路线距离edge属性来模拟类似于您的查询的内容。该示例仅使用一个机场使其保持简单。首先只是创建分数列表...
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]]
最后创建平均值
gremlin> g.V().has('airport',......6> constant(-1)).
......7> mean())
==>[airport:SAF,mean:0.5]
再次编辑
如果edge属性可能不存在,则可以执行以下操作...
gremlin> g.V().has('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]]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。