Neo4j - 复杂的密码查询 - 需要外连接

Posted

技术标签:

【中文标题】Neo4j - 复杂的密码查询 - 需要外连接【英文标题】:Neo4j - Complex cypher query - needs outer join 【发布时间】:2015-07-15 13:35:25 【问题描述】:

我正在使用 Neo4j 图形数据库,我正在尝试构建一个复杂的密码查询

我有以下节点和关系:

节点

客户节点 品牌节点 Segment 节点(具有“MaxReservationsPerBrandPerMonth”属性) 预留节点

关系

每个客户都细分到一个细分市场 客户可以与预订有 cust_reserved 关系 每个预订都与一个品牌相关

我想获取 客户数量,这些客户有资格为特定品牌进行新预订。

因此,我需要计算给定品牌的每个客户的预订量,并与该客户细分的 MaxReservationsPerBrandPerMonth 进行比较。

请注意,未预订的客户也应计算在内

感谢您的支持。

编辑 1

在尝试迈克尔第一次查询后,查询是:

PROFILE MATCH (c:Customer)
// also count customers without reservations (make this match optional)
OPTIONAL MATCH (c)-[:CUST_RESERVED]->(r:Reservation)-[:RESERVATION_FOR]->(b:brand BRAND_ID: "3")
// count reservations by brand and customers
WITH c, b, count(*) as reservations
MATCH (c)-[:SEGMENTED]->(s:segment)
WHERE reservations < s.max_sms_per_month
// aggregate count customers per brand
RETURN b.NAME, count(distinct c) as customers

查询结果:

结果出乎意料,我想获得“本田”品牌的合格客户,结果只有5个(之前已经为本田预留,但仍然合格,因为他们还没有达到最大值),结果应该是 998734(所有客户)

查询资料:Query profile

数据集:here SQL 中需要的查询:here

编辑 2

Michael 的第二个查询在 20 秒左右就发挥了作用,谢谢 Michael 我需要在某些预订期间包含一些日期逻辑来检查预订:)

【问题讨论】:

尝试为:brand(BRAND_ID)创建一个约束/索引(注意你应该将拼写修正为:Brand(brandId) 当您按品牌名称分组时(正如您所说的“符合品牌条件”,这是我所期望的)。 【参考方案1】:

您已经说清楚了,请参阅我们的在线指南,了解如何解决您的用例问题:http://neo4j.com/developer/guide-data-modeling/

所以你的模式是

(:Customer)-[:IS_SEGMENTED]->(:Segment MaxReservationsPerBrandPerMonth:int)
(:Customer)-[:HAS_RESERVED]->(:Reservation)
(:Reservation)-[:FOR_BRAND]->(:Brand)

你的问题:

    我想了解有资格为特定品牌进行新预订的客户数量。 因此,我需要计算给定品牌的每位客户的预订量,并与该客户细分的 MaxReservationsPerBrandPerMonth 进行比较。 请注意,未预订的客户也应计算在内
MATCH (c:Customer)
// also count customers without reservations (make this match optional)
OPTIONAL MATCH (c)-[:HAS_RESERVED]->(r:Reservation)-[:FOR_BRAND]->(b:Brand)
// count reservations by brand and customers
WITH c, b, count(*) as reservations
MATCH (c)-[:IS_SEGMENTED]->(s:Segment)
WHERE s.MaxReservationsPerBrandPerMonth < reservations
// aggregate count customers per brand
RETURN b.name, count(distinct c) as customers

“如果没有保留的客户应该算什么”为0?

更新:查询非可选预订

问题:没有预订的客户会与哪个品牌相关/检查?由于预订数为 0,那么 MaxReservationsPerBrandPerMonth 必须为 -1 才能被选中?所以我们也可以让它成为非可选的?还请分享您获得的带有 PROFILE 前缀的查询计划。

MATCH (c:Customer)-[:HAS_RESERVED]->(r:Reservation)-[:FOR_BRAND]->(b:Brand)
// count reservations by brand and customers
WITH c, b, count(*) as reservations
MATCH (c)-[:IS_SEGMENTED]->(s:Segment)
WHERE s.MaxReservationsPerBrandPerMonth < reservations
// aggregate count customers per brand
RETURN b.name, count(distinct c) as customers

更新 2,查询优化尝试

您的查询是图全局查询,因此它会涉及许多路径,您已经有至少 10M 的 db-hits。

我可能会稍微改变一下那个查询:

我不再 100% 确定品牌是如何在这里发挥作用的: 没有数据集也有点困难!

MATCH (b:brand BRAND_ID: "3")
MATCH (c:Customer) 
WITH b,c, size((c)-[:CUST_RESERVED]->()) as total_res
WITH b,c,total_res, 
     case when total_res > 0 then last(nodes(head((c)-[:SEGMENTED]->(:segment)))).max_sms_per_month else 10 end as max_sms_per_month,
     case when total_res > 0 then size((c)-[:CUST_RESERVED]->()-[:RESERVATION_FOR]->(b)) else 0 end as brand_res
WHERE total_res = 0 OR total_res < max_sms_per_month OR brand_res < max_sms_per_month
// TODO what to do with reservations by brand?   
RETURN b.NAME, count(distinct c) as customers

【讨论】:

非常感谢迈克尔,它就像一个魅力,我只是把它改成了预订 Michael,这里恐怕有一种笛卡尔积,我再次执行查询,Neo4j 服务器挂了 这是一个全局查询,如果您在查询前加上 PROFILE,您会看到它找到了多少条路径。您可以与我个人共享数据库吗? neo4j.com 的迈克尔 问题可能是您的“可选”检查。我们可以通过使用 UNION 来改变这一点,我更新了答案以反映替代方案。 再次感谢@Michael,让我进一步澄清一下,我正在开发向不同品牌的客户发送广告短信的应用程序,并且限制是,根据客户的细分,他们无法接收每个品牌的短信比他们的细分中定义的要多,所以当我为某个品牌开始新的活动时,我想运行查询以获取符合条件的客户数量以接收该品牌的短信,希望你得到我,我会再次回复明天抱歉,这里是凌晨 1 点 :)

以上是关于Neo4j - 复杂的密码查询 - 需要外连接的主要内容,如果未能解决你的问题,请参考以下文章

Neo4j 图中的密码查询

Neo4J 密码查询“继承”术语

neo4j 密码匹配命令连接

Neo4j 密码查询以获取与特定其他节点没有关系的所有节点

在庞大的数据集上优化 Neo4j 密码查询

在 neo4j 密码查询中使用多个匹配子句不会返回任何结果