查找在同一城市运营的客户

时间:2015-10-14 20:59:37

标签: neo4j cypher

我有客户节点,第二个节点是地址

有客户LOCATED_IN地址

我想让所有位于同一城市的客户,返回城市,计数和客户名称按计数desc排序

MATCH (c:Customer)-[:LOCATED_IN]->(a:Address)
WITH a.city as city, count(*) as count
WHERE count > 1
RETURN city, count, collect(c.name)
ORDER BY count DESC;

c未定义(第4行,第29栏(偏移:120)) "返回城市,统计,收集(c.name)"                              ^ Neo.ClientError.Statement.InvalidSyntax

如果我删除" collect(c.name)"

查询工作正常但是,那么我想念一些我想要的信息......

2 个答案:

答案 0 :(得分:2)

正如TrueDub所说,您需要在WITH子句中随身携带您想要返回的所有内容。 但是,您无法将a.citycount(*) c并期望count(*)成为城市中的客户数量。 原因是,为了计算每个城市的客户,您需要汇总客户。 但在这里,您将个人客户(c)带到您身边,并使个人客户阻止客户聚合。 这就是你获得1的原因,因为没有聚合的计数只意味着计算单个结果项。

您可以通过在WITH子句中引入两件事来轻松解决此问题:地址/城市和客户集合。当您携带个人地址/城市并汇总客户时,您将获得每个城市的客户汇总。

WITH a.city, COLLECT(c) as customers

然后您可以过滤该集合的大小。

WHERE SIZE(customers) > 1

一个额外的和未经请求的注释:您的查询现在的工作方式,它在进行过滤之前读取属性。 这样做效率不高,因为它会读取可能会被丢弃的结果项的属性。 根据您的:Address节点的外观 1 ,您可以在不触及任何属性的情况下进行收集和过滤。 这对性能来说是理想的。 请参阅Michael Hunger 5 Secrets to More Effective Neo4j 2.2. Query Tuning中的提示#4:推迟财产访问

MATCH (customer:Customer)-[:LOCATED_IN]->(address:Address)
WITH address, COLLECT(customer) as customersAtAddress
WHERE SIZE(customersAtAddress) > 1
RETURN address.city as city,
       SIZE(customersAtAddress) as customerCount,
       EXTRACT(customer IN customersAtAddress | customer.name) as customerNames

现在,查询会在获取任何属性之前排除那些只有一个客户的地址,并且客户位于每个地址的集合中。由于客户在一个集合中,我们使用EXTRACT来浏览集合并读取每个客户的名称。 EXTRACT会返回一个新集合,因此您的结果将类似于。

city        customerCount    customerNames
-------------------------------------------------------------------------------
 Säby        2                [Anders Järhed, Matilda Fridlund]
 Frinnaryd   3                [Bo-Erik Jonsson, Annelie Sjöström, Ulf Eliasson]
  

1 我说“取决于你的:Address节点的样子,因为我不知道你是否有许多共享一个城市的地址节点。如果你这样做,那么您有一个不同的问题。我建议的查询(以及您自己的查询)将为您提供每个地址节点的客户集合。如果您有两个地址节点用于城市Säby,那么您将获得两个结果Säby的项目,有两个不同的客户集合。解决方案可能是稍微更改您的模型,并将城市移动到自己的节点,与“拥有”该城市的不同地址有关系。我知道如果是这种情况,也许我可以就此提出建议。

最后,上面的查询计算了两次集合的大小。这不是那么昂贵,而且值可能是由查询引擎缓存的。但是如果您想确定,可以添加另一个WITH子句来计算一次值并将其绑定到标识符。然后查询出现为

MATCH (customer:Customer)-[:LOCATED_IN]->(address:Address)
WITH address, COLLECT(customer) as customersAtAddress
WITH address, customersAtAddress, COUNT(customersAtAddress) as customerCount
WHERE SIZE(customersAtAddress) > 1
RETURN address.city as city,
       customerCount,
       EXTRACT(customer IN customersAtAddress | customer.name) as customerNames

答案 1 :(得分:1)

我认为你需要将c带入WITH子句,如下所示:

MATCH (c:Customer)-[:LOCATED_IN]->(a:Address)
WITH a.city as city, count(*) as count, c
WHERE count > 1
RETURN city, count, collect(c.name)
ORDER BY count DESC;