查找一个人没有购买的所有物品,并计算购买次数

时间:2019-01-20 15:38:44

标签: neo4j cypher gremlin

我有一个看起来像这样的图。

enter image description here

我想找到所有使用Gremlincypher购买了相同物品的人们所购买的物品。

基本上我想在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

35仅被购买了一次,而4被购买了2次。 有什么问题吗?

1 个答案:

答案 0 :(得分:1)

密码对路径感兴趣,您的MATCH会找到以下内容:

  • 通过Rexter到项3的2条路径(通过项2和1)
  • 通过管道到项目5的2条路径(通过项目1和2)
  • 通过Rexter和Pipes(通过每个人的项目1和2)到项目4的4条路径

基本上,这些项目被计算了多次,因为每个人都有一条路径通过Gremlin通过不同的常用项目到达同一个人。

要获得准确的计数,您需要匹配不同的r用户,然后才匹配r用户购买的商品(只要他们不在商品集中) ,或者您需要进行整个比赛,但是在进行计数之前,请针对每个人获取不同的商品,这样每个人的每个商品只能出现一次...然后获取每个商品的计数(所有人的总数) )。

这是使用第二种方法的查询

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

您应该在图形中使用标签,并且应该在查询中使用标签,以便利用索引并快速在图形中找到起点。在您的情况下,即使更多的节点和更多的:Persons被添加到图形中,在:Person(name)上的索引以及在查询中使用:Person标签,也应该使此操作快速进行。

编辑

如果您只是在寻找查询的简洁性,并且没有足够大的图形来考虑性能,那么您可以使用原始查询,但增加一行以获取{{ 1}}和r,然后再计算项目。这样可以确保在您获得计数时,每个人一次只能计数一次。

请注意,放弃了用于处理排除项目的优化(它将对每个项目进行模式匹配,而不是对购买项目的集合进行汇总并进行集合成员资格检查),并且在进行属性访问而不是进行属性访问时对项目进行汇总仅在按节点聚合之后。

n_item

我正在为您的比赛添加一个快捷方式,使用:BOUGHT * 2表示到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 的两个:BOUGHT跃点,因为我们并不真正关心中间的项目。