Почему я получаю предупреждение "Декартово произведение"?
Я все еще пытаюсь понять, почему я получаю предупреждение о декартовой системе для определенного формата для запроса в neo4j, а не для другого. Вот как я настроил свою базу данных:
CREATE (q:Form {version: "1.0"})
CREATE (q:Question {text: "Sector de la empresa", active: true})
Затем я попробовал следующий запрос:
MATCH
(f:Form {version: "1.0"}),
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
Тем не менее, я получаю следующее предупреждение:
This query builds a cartesian product between disconnected patterns.
If a part of a query contains multiple disconnected patterns,
this will build a cartesian product between all those parts.
This may produce a large amount of data and slow down query processing.
While occasionally intended, it may often be possible to reformulate the
query that avoids the use of this cross product, perhaps by adding a
relationship between the different parts or by using OPTIONAL MATCH
(identifier is: (q))
Когда я использую следующий запрос, он не дает мне это предупреждение:
MATCH (f:Form {version: "1.0"})
WITH f
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
ни когда я использую этот запрос:
MATCH (f:Form {version: "1.0"})
MATCH (q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
Я использовал следующую статью в качестве ресурса, но он все еще не полностью ответил на мой вопрос: почему neo4j предупреждает: "Этот запрос строит декартово произведение между несвязанными образцами"?
Почему я получаю декартово произведение для некоторых форматов запроса, а не для других? Кроме того, я не совсем понимаю, что такое предупреждение о декартовых произведениях.
2 ответа
Если ты MATCH
На двух разных ярлыках без каких-либо связей между ними, вы получите это предупреждение. Причина в том, что если вы делаете:
MATCH (a:Foo), (b:Bar)
Задача Neo4j - найти все возможные комбинации этих двух узлов. Итак, для первого матча a
он вернет строку для каждого совпадения b
, для второго матча a
он снова вернет строку для каждого совпадения b
, и так далее. Так вы получите (number of Foo nodes) x (number of Bar nodes)
Всего строк в вашем результате. Поскольку ваша база данных растет, это очень плохо сказывается на производительности.
Я вижу, что вы фильтруете version
за Form
а также text
за Question
, так что это поможет. Это может даже дать вам только один Form
узел и один Question
узел. Так что пока у вас есть индекс на Form(version)
а также Question(text)
запрос должен быть довольно быстрым. Neo4j не может сказать (или, по крайней мере, в настоящее время не реализован, чтобы иметь возможность определить), сколько строк будет возвращено, поэтому он выдает предупреждение о том, что ваш запрос может быть потенциально медленным.
Они все декартовы
Прочитав ваш вопрос, на секунду там мой мир шифров рухнул - все три запроса должны включать декартово произведение.
Проверив (как на консоли, так и на локальной БД - обе версии 3.3.0), выясняю, что я в здравом уме - все они связаны с декартовым произведением:
Почему в первом случае есть только предупреждение (все еще в версии 3.3.0, я понятия не имею - вам просто нужно запустить планировщик, чтобы выяснить это, и если это не сработает, то предупреждение? Какая-то тупая шифровальная логика?
Основы Cypher
Cypher-запросы состоят из частей, каждый из которых может быть обновлен (записан) или прочитан.
Что касается прочитанных частей, вот что происходит:
- Neo4j выбирает отправную точку, которая, по его мнению, даст наименьшее количество "хитов". Он пройдет через каждый из этих хитов...
- ... прохождение графа с использованием шаблона "узел / отношение".
- Это повторяется до тех пор, пока больше не будут сопоставлены шаблоны.
Если у вас есть что-то вроде этого:
(a {name:'Bill'})-->(b:Dog)
План может выглядеть примерно так.
- Для каждого узла (АКА
AllNodeScan
):- Фильтр на основе предиката (
name == 'bill'
) - Получить все исходящие
-->
отношения - Для каждого отношения:
- Получить конечный узел
- Фильтр на основе предиката (
:Dog
)
- Фильтр на основе предиката (
Важно то, что пока найти (a)
нам нужно сканировать каждый узел. Но мы просто пересекаем график, чтобы найти (b)
с - нет AllNodeScan
для последнего.
(Есть варианты AllNodeScan
см. Операторы запуска узла
Когда ваш запрос выглядит примерно так:
MATCH (f:Form {version: "1.0"}), (q:Question {text: "Sector de la empresa"})
Нео вынужден сделать AllNodeScan
для обоих f
а также q
- Там нет шаблона для перемещения между ними. Это может потенциально создать результирующий набор размера f * q, который может быть огромным.