【问题标题】:find all items that wasn't bought by a person and count the times it was bought找出所有不是某人购买的物品并计算购买次数
【发布时间】:2019-01-20 15:38:44
【问题描述】:

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

我想查找所有购买过与Gremlin 使用cypher 相同商品的人购买的商品。

基本上我想模仿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 次。 有什么问题?

【问题讨论】:

    标签: neo4j cypher gremlin


    【解决方案1】:

    Cypher 对路径感兴趣,您的 MATCH 发现以下内容:

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

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

    要获得准确的计数,您要么需要匹配不同的 r 用户,然后再匹配 r 用户购买的商品(只要它们不在 Gremlin 购买的商品集合中) , 或者您需要进行整个匹配,但在进行计数之前,请获取关于每个人的不同项目,以便每个人的每个项目仅出现一次......然后获取每个项目的计数(对所有人进行计数)。

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

    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 标签的使用应该会加快速度,即使更多节点和更多 :Persons 添加到图表中也是如此。

    编辑

    如果您只是希望查询的简洁性,并且没有足够大的图表来解决性能问题,那么您可以使用原始查询,但添加一行额外的行以获得 @987654324 的不同行@ 和 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
    

    我在你的比赛中添加一个快速快捷方式,使用 :BOUGHT*2 表示两个 :BOUGHT 跳跃到r,因为我们并不真正关心中间的项目。

    【讨论】:

    • 嗯...Cypher 上的查询不像 Gremlin 上那样直观。 Cypher 不是为此类查询而设计的?
    • 不同的是分组。如前所述,Cypher 是以路径为中心的,它正在寻找到相关节点的所有可能路径,并且由于查询多次通过相同的人(与您的起始人的每个共同项目),因此计数已关闭。如果您不需要首先获得不同的人(或不同的人/项目组合),那么原始方法将是正确的。这个特殊的用例恰好更冗长。此外,在处理排除项目和最后进行属性访问方面,我在性能方面犯了错误。
    • If you had no need to get distinct persons first (or distinct person/item combinations) hm 可以避免吗?我只需要物品
    • 不同的人/项目对是必要的,这样你的计数是准确的。被抛弃的是不同的人通过不同的路径/项目被多次匹配,所以在某些时候(无论是在人级别还是在人/项目级别),您必须在聚合之前获得不同的值。如果您只需要没有计数的建议项目,那很容易,只需执行完整匹配模式和RETURN DISTINCT n_item.id。我猜你需要计数,每个匹配的人 1 个项目计数。
    • 是的,我需要计数,因为我想对其进行排名(尽管我可能可以在这里应用一些算法)
    猜你喜欢
    • 1970-01-01
    • 2019-09-14
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多