重组大型密码联合查询
Restructuring a large cypher union query
我有一个非常长的使用联合的密码查询,但是,有一些公共语句(粗体)在两个查询中重复出现。有没有一种方法可以分解,甚至存储公共语句的结果集,然后在以后对它们进行分支和合并?我调查了使用 with、collect 和可选匹配,但无济于事。
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE( FILTER(c in subs WHERE c.level ="CAPE")) as cape
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
匹配 (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs) AND NOT (p)-->(:Combo)
RETURNp
联盟
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE( FILTER(c in subs WHERE c.level ="CAPE")) as cape
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
匹配 (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs)
匹配 (p)-[:requires]->(c:Combo)-[:contains]->(s:Subject)
WITH p, c, subs, collect(s) 作为列表
WITH p, subs, collect({amt:c.amt, set:list}) 作为组合
WHERE ALL(combo in combos where combo.amt <= size(apoc.coll.intersection(subs, combo.set)))
RETURNp
一些额外的上下文;所有程序节点都连接到至少 1 个称为强制性主题节点。此外,一些程序节点还连接到一个或多个组合节点。在这种情况下,需要对程序进行更多检查,我将对组合和非组合这两种类型的查询进行合并。
首先,有几点重要说明。
Cypher 不规定如何检索信息。这种优化是Cypher规划器应该处理的事情(现在没有,但将来可能会改变)
Cypher 运行s UNION 并行查询,这意味着除非您将 Neo4j 服务器推到极限,否则查询时间应该与只有运行 两个查询中成本较高的一个。 (请注意,由于内存缓存,重复 运行s 可能会更快)因此,如果时间是您的问题,那不应该是。如果 DBHits 是问题,那么现在您不应该使用 UNION。
也就是说,我可以通过添加 OPTIONAL
和 SIZE(combo.set)=0 OR
来组合这两个查询。添加评论以解释逻辑
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE(FILTER(c in subs WHERE c.level ="CAPE")) as capes
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
MATCH (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs)
OPTIONAL MATCH (p)-[:requires]->(c:Combo)-[:contains]->(s:Subject)
// Where c is null, list is empty
WITH p, c, subs, collect(s) as list
// If c is null, combos is a list of empty lists
WITH p, subs, collect({amt:c.amt, set:list}) as combos
// SIZE(combo.set)=0 is true if the list is null or an empty list
WHERE ALL(combo in combos where SIZE(combo.set)=0 OR combo.amt <= size(apoc.coll.intersection(subs, combo.set))) RETURN p
我有一个非常长的使用联合的密码查询,但是,有一些公共语句(粗体)在两个查询中重复出现。有没有一种方法可以分解,甚至存储公共语句的结果集,然后在以后对它们进行分支和合并?我调查了使用 with、collect 和可选匹配,但无济于事。
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE( FILTER(c in subs WHERE c.level ="CAPE")) as cape
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
匹配 (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs) AND NOT (p)-->(:Combo)
RETURNp
联盟
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE( FILTER(c in subs WHERE c.level ="CAPE")) as cape
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
匹配 (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs)
匹配 (p)-[:requires]->(c:Combo)-[:contains]->(s:Subject)
WITH p, c, subs, collect(s) 作为列表
WITH p, subs, collect({amt:c.amt, set:list}) 作为组合
WHERE ALL(combo in combos where combo.amt <= size(apoc.coll.intersection(subs, combo.set)))
RETURNp
一些额外的上下文;所有程序节点都连接到至少 1 个称为强制性主题节点。此外,一些程序节点还连接到一个或多个组合节点。在这种情况下,需要对程序进行更多检查,我将对组合和非组合这两种类型的查询进行合并。
首先,有几点重要说明。
Cypher 不规定如何检索信息。这种优化是Cypher规划器应该处理的事情(现在没有,但将来可能会改变)
Cypher 运行s UNION 并行查询,这意味着除非您将 Neo4j 服务器推到极限,否则查询时间应该与只有运行 两个查询中成本较高的一个。 (请注意,由于内存缓存,重复 运行s 可能会更快)因此,如果时间是您的问题,那不应该是。如果 DBHits 是问题,那么现在您不应该使用 UNION。
也就是说,我可以通过添加 OPTIONAL
和 SIZE(combo.set)=0 OR
来组合这两个查询。添加评论以解释逻辑
MATCH (s:Subject), (p:Programme)
WHERE s.name in ['A', 'B', 'C']
WITH collect(s) as subs, p
WITH p, subs, SIZE(FILTER(c in subs WHERE c.level ="CSEC")) as csecs, SIZE(FILTER(c in subs WHERE c.level ="CAPE")) as capes
WHERE p.csec_passes <= csecs AND p.cape_passes <= capes
MATCH (p:Programme)-[:requires]->(s:Subject)
WITH p, subs, COLLECT(s) AS mandatories WHERE ALL(n IN mandatories WHERE n IN subs)
OPTIONAL MATCH (p)-[:requires]->(c:Combo)-[:contains]->(s:Subject)
// Where c is null, list is empty
WITH p, c, subs, collect(s) as list
// If c is null, combos is a list of empty lists
WITH p, subs, collect({amt:c.amt, set:list}) as combos
// SIZE(combo.set)=0 is true if the list is null or an empty list
WHERE ALL(combo in combos where SIZE(combo.set)=0 OR combo.amt <= size(apoc.coll.intersection(subs, combo.set))) RETURN p