Реструктуризация большого запроса на шифрование - PullRequest
0 голосов
/ 05 ноября 2018

У меня очень длинный запрос на шифрование, использующий объединение, однако есть некоторые общие утверждения (выделены жирным шрифтом), которые повторяются в обоих запросах. Есть ли способ, которым я могу выделить или даже сохранить результирующий набор общих операторов, чтобы потом их разветвить и объединить? Я исследовал использование с, собирать и необязательное совпадение, но безрезультатно.

МАТЧ (s: Тема), (p: Программа)
ГДЕ s.name в ['A', 'B', 'C']
WITH собирать (-ять) как подпрограммы, p
WITH p, подпункты, РАЗМЕР (FILTER (c в подпрограммах WHERE c.level = "CSEC")) как csecs, SIZE (FILTER (c в подпрограммах WHERE c. уровень = "МЫС")) как накидки
ГДЕ p.csec_passes <= csecs И p.cape_passes <= capes <BR> MATCH (p: Программа) - [: требуется] -> (s: Тема)

С p, sub, COLLECT (s) как мандаторы WHERE ALL (n в мандаториях WHERE n IN сабвуферов) И НЕ (p) -> (: Combo)
ВОЗВРАТ р

UNION

МАТЧ (s: Тема), (p: Программа)
ГДЕ s.name в ['A', 'B', 'C']
WITH collect (s) как подпрограммы, p
WITH p, subs, РАЗМЕР (FILTER (c в подпрограммах WHERE c.level = "CSEC")) как csecs, SIZE (FILTER (c в подпрограммах WHERE c. уровень = "МЫС")) как накидки
ГДЕ p.csec_passes <= csecs И p.cape_passes <= capes <BR> MATCH (p: Программа) - [: требуется] -> (s: Тема)

С p, sub, COLLECT (s) в качестве мандаторий WHERE ALL (n в мандатах, где n в sub)
MATCH (p) - [: требуется] -> (c: комбинированный) - [: содержит] -> (s: Тема)
WITH p, c, subs, сбор (ы) в виде списка
WITH p, subs, собирать ({amt: c.amt, set: list}) как комбинации
WHERE ALL (комбо в комбинации, где combo.amt <= размер (apoc.coll.intersection (subs, combo.set))) ВОЗВРАТ р </p>

Некоторый дополнительный контекст; все программные узлы подключены как минимум к одному предметному узлу, который называется обязательным. Кроме того, некоторые программные узлы также связаны с одним или несколькими комбинированными узлами. В таких случаях нужно проводить больше проверок программ, я объединяю запросы для обоих типов, комбинированные и некомбинированные.

1 Ответ

0 голосов
/ 05 ноября 2018

Сначала пара важных замечаний.

  1. Сайфер не определяет способ получения информации. Такого рода оптимизация - это то, что планировщик Cypher должен обработать (это не сейчас, но может измениться в будущем)

  2. Cypher выполняет запросы UNION параллельно, что означает, что, если вы не выдвигаете свой сервер Neo4j до его пределов, время запроса должно быть практически неразличимо, если вы выполняли только более дорогой из двух запросов. (Обратите внимание, что повторные запуски могут быть быстрее из-за кэш-памяти в памяти). Так что, если время - ваша проблема, это не должно быть. Если проблема в 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
...