我有一个图表,看起来像这样。
我想找到人们购买的所有物品,他们使用cypher
购买了与Gremlin
相同的物品。
基本上,我想要模仿gremlin
示例中的查询,如下所示
g.V().has("name","gremlin")
.out("bought").aggregate("stash")
.in("bought").out("bought")
.where(not(within("stash")))
.groupCount()
.order(local).by(values,desc)
我试着这样做
MATCH (n)-[:BOUGHT]->(g_item)<-[:BOUGHT]-(r),
(r)-[:BOUGHT]->(n_item)
WHERE
n.name = 'Gremlin'
AND NOT (n)-[:BOUGHT]->(n_item)
RETURN n_item.id, count(*) as frequency
ORDER by frequency DESC
但它似乎没有正确计算frequencies
-它们似乎是两倍大。
4 - 4
5 - 2
3 - 2
而3
和5
只被买了一次,4
被买了两次。有什么问题吗?
发布于 2019-01-21 10:04:42
Cypher对路径感兴趣,您的匹配会找到以下内容:
基本上,这些项目会被计算多次,因为通过Gremlin的不同常见项目,每个人都有多条通往同一项目的路径。
为了获得准确的计数,你要么需要匹配不同的r
用户,然后只匹配r
用户购买的商品(只要他们不在Gremlin购买的商品集合中),要么你需要进行整个匹配,但在进行计数之前,获取每个人的不同商品,这样每个人的商品只发生once...then获得每件商品的数量(所有人的数量)。
下面是一个使用第二种方法的查询
MATCH (n:Person)-[:BOUGHT]->(g_item)
WHERE n.name = 'Gremlin'
WITH n, collect(g_item) as excluded
UNWIND excluded as g_item // now you have excluded list to use later
MATCH (g_item)<-[:BOUGHT]-(r)-[:BOUGHT]->(n_item)
WHERE r <> n AND NOT n_item in excluded
WITH DISTINCT r, n_item
WITH n_item, count(*) as frequency
RETURN n_item.id, frequency
ORDER by frequency DESC
您应该在图形中使用标签,并且应该在查询中使用它们,以便利用索引并在图形中快速找到起点。在您的例子中,在:Person(name)上建立索引,并在查询中使用:Person标签,即使向图中添加了更多的节点和更多的:Person,也应该会更快。
编辑
如果您只是在寻找查询的简洁性,并且没有足够大的图,而性能将是一个问题,那么您可以使用原始查询,但在计算项目之前添加一行以获得不同的r
和n_item
行。这确保了当您获得计数时,每个人只计算一次物品。
请注意,放弃了处理排除项的优化(它将对每个项执行模式匹配,而不是聚合购买项的集合并执行集合成员关系检查),并且它在进行属性访问时聚合项,而不是仅在节点聚合之后才进行属性访问。
MATCH (n:Person)-[:BOUGHT*2]-(r)-[:BOUGHT]->(n_item)
WHERE n.name = 'Gremlin'
WITH DISTINCT n, r, n_item
WHERE NOT (n)-[:BOUGHT]->(n_item)
RETURN n_item.id, count(*) as frequency
ORDER by frequency DESC
我在您的匹配中添加了一个快捷方式,使用: about *2来指示两个:已购买的到r
的跳数,因为我们并不真正关心中间的项目。
https://stackoverflow.com/questions/54278050
复制