Почему neo4j предупреждает: "Этот запрос создает декартово произведение между отключенными шаблонами"?

Я определяю связь между двумя объектами, Gene и Chromosome, в том, что я считаю простым и обычным способом, после импорта данных из CSV:

MATCH (g:Gene),(c:Chromosome)
WHERE g.chromosomeID = c.chromosomeID
CREATE (g)-[:PART_OF]->(c);

Тем не менее, когда я это делаю, neo4j (браузер UI) жалуется:

Этот запрос создает декартовое произведение между несвязанными шаблонами. Если часть запроса содержит несколько несвязанных шаблонов, это приведет к созданию декартова продукта между всеми этими частями. Это может привести к большому количеству данных и замедлить обработку запросов. Иногда изредка можно переформулировать запрос, который позволяет избежать использования этого перекрестного продукта, возможно, путем добавления отношения между различными частями или с помощью ДОПОЛНИТЕЛЬНОГО МАТЧИ (идентификатор: (c)).

Я не понимаю, в чем проблема. chromosomeID - очень простой внешний ключ.

Ответ 1

Браузер сообщает вам, что:

  • Он обрабатывает ваш запрос, проводя сравнение между каждым экземпляром Gene и каждым экземпляром Chromosome. Если ваша БД имеет гены G и хромосомы C, тогда сложность запроса O(GC). Например, если мы работаем с геномом человека, есть 46 хромосом и, возможно, 25000 генов, поэтому БД должна была бы выполнить сравнения 1150000.
  • Возможно, вы сможете улучшить сложность (и производительность), изменив ваш запрос. Например, если создал индекс на :Gene(chromosomeID) и изменил запрос так, чтобы мы первоначально согласовали только с node с наименьшей мощностью (46 хромосом), мы выполнили бы только O(G) (или 25000) "сравнения", и эти сравнения фактически были бы быстрыми поисками индекса! Это подход должен быть намного быстрее.

    Как только мы создали индекс, мы можем использовать этот запрос:

    MATCH (c:Chromosome)
    WITH c
    MATCH (g:Gene) 
    WHERE g.chromosomeID = c.chromosomeID
    CREATE (g)-[:PART_OF]->(c);
    

    Он использует предложение WITH, чтобы принудительно выполнить первое предложение MATCH, избегая декартова продукта. Второе предложение MATCHWHERE) использует результаты первого предложения MATCH и индекс, чтобы быстро получить точные гены, принадлежащие каждой хромосоме.

Ответ 2

Как отмечает logisima в комментариях, это всего лишь предупреждение. Соответствие декартова продукта медленное. В вашем случае это должно быть хорошо, так как вы хотите подключить ранее не подключенные узлы Gene и Chromosome, и вы знаете размер декартова продукта. Не так много хромосом и небольшого числа генов. Если бы вы использовали MATCH, например. гены на белки могут вызвать удар.

Я думаю, что предупреждение предназначено для других проблемных запросов:

  • если вы MATCH декартовой продукт, но вы не знаете, есть ли связь, которую вы могли бы использовать OPTIONAL MATCH
  • если вы хотите MATCH как Gene, так и Chromosome без каких-либо отношений, вы должны разделить запрос

Если ваш запрос занимает слишком много времени или не заканчивается, вот еще один вопрос, дающий некоторые подсказки по оптимизации декартовых продуктов: Как оптимизировать запросы Neo4j Cypher с несколькими совпадениями node (Декартовый продукт)