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 - 复杂的密码查询 - 需要外连接的主要内容,如果未能解决你的问题,请参考以下文章