Как заставить CREATE работать УНИКАЛЬНО с помощью подзапроса?

StackOverflow https://stackoverflow.com//questions/20002740

  •  20-12-2019
  •  | 
  •  

Вопрос

У меня есть запрос, подобный этому:

MATCH left, right 
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6]) 
WITH left, right 
  LIMIT 1 
RETURN left, right 
UNION MATCH left, right 
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6]) 
WITH left, right 
  SKIP 4 LIMIT 1 
RETURN left, right 
UNION MATCH left, right 
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6]) 
WITH left, right 
  SKIP 8 LIMIT 1 
RETURN left, right
CREATE UNIQUE left-[rel:FRIEND]->right 
RETURN rel;

В общем, я просто создаю набор данных, чтобы позже использовать его в инструкции CREATE UNIQUE.
Очевидно, что это не работает - анализатор запросов говорит, что я могу использовать предложение RETURN только один раз.Мой вопрос в том, как составить набор данных в этом случае?Я попытался назначить псевдоним и использовать его в CREATE UNIQUE - тоже не смог заставить его работать.Что я делаю не так?Возможен ли вообще такой сценарий?

Это было полезно?

Решение

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

Для начала, вот адаптация вашего запроса, который использует SKIP и LIMIT без RETURN или UNION.

MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right 
    LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH [rel] as rels  //If you want to return the relationship later you can put it in a collection and bring it WITH
MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right, rels 
    SKIP 4 LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH rels + [rel] as rels
MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right, rels 
    SKIP 8 LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH rels + [rel] as rels
RETURN LENGTH(rels), rels  // You can return the relationships here but SKIP/LIMIT does its job also if you don't return anything

Но этот запрос немного дикий.На самом деле это три запроса, где два были искусственно втиснуты в качестве подзапросов первого.Он заново сопоставляет одни и те же узлы в каждом подзапросе, и на самом деле ничего не получается, если выполнять запросы таким образом, а не по отдельности (на самом деле это медленнее, потому что в каждом подзапросе вы сопоставляете также узлы, которые, как вы знаете, вы не будете использовать).

Итак, мое первое предложение - использовать START вместо того, чтобы MATCH...WHERE при получении узлов по идентификатору.В нынешнем виде запрос привязывает каждый узел в базе данных как "левый", а затем каждый узел в базе данных как "правый", и затем он отфильтровывает все узлы, привязанные к "левому", которые не соответствуют условию в WHERE предложение, а затем то же самое для "правильного".Поскольку эта часть запроса повторяется три раза, все узлы в базе данных привязываются в общей сложности шесть раз.Это дорого стоит для создания трех отношений.Если вы используете START вы можете сразу же связать нужные вам узлы.На самом деле это не ответ на ваш вопрос, но так будет быстрее, а запрос - чище.Итак, используйте START чтобы получить узлы по их внутреннему идентификатору.

START left = node(1,2,3), right = node(4,5,6)

Второе, о чем я думаю, - это разница между узлами и "путями" или "элементами результата" при сопоставлении шаблонов.Когда вы связываете три узла "слева" и три других узла "справа", у вас получается не три элемента результата, а девять.Для каждого узла, связанного "слева", вы получаете три результата, потому что есть три возможных "справа", с которыми его можно объединить.Если вы хотите соотнести каждое "левое" с каждым "правым", отлично.Но я думаю, что то, что вы ищете, - это результирующие элементы (1),(4), (2),(5), (3),(6), и хотя кажется удобным связать три "левых" узла и три "правых" узла в одном запросе с коллекциями идентификаторов узлов, затем вам нужно выполнить всю эту фильтрацию, чтобы избавиться от 6 нежелательных совпадений.Запрос становится сложным и громоздким, и на самом деле это медленнее, чем выполнение запросов по отдельности.Другой способ сказать это - сказать , что (1)-[:FRIEND]->(4) это отдельный шаблон, не связанный (релевантно) с другими шаблонами, которые вы создаете.Все было бы по-другому, если бы вы хотели создавать (1)-[:FRIEND]->(2)<-[:FRIEND]-(3), тогда вы хотели бы обрабатывать эти три узла вместе.Может быть, вы просто изучаете второстепенное использование cypher, но я подумал, что должен указать на это.Кстати, используя SKIP и LIMIT этот способ немного неуместен, на самом деле они не предназначены для сопоставления с образцом и фильтрации.Это также непредсказуемо, если только вы не используете ORDER BY, поскольку нет никакой гарантии, что результаты будут в определенном порядке.Вы не знаете, какой именно результирующий элемент передается дальше.В любом случае, в данном случае, я думаю, было бы лучше связать узлы и создать связь в трех отдельных запросах.

START left = node(1), right = node(4)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel

START left = node(2), right = node(5)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel

START left = node(3), right = node(6)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel

Поскольку вы уже знаете, что вам нужны эти три пары, а не, скажем, (1),(4),(1),(5),(1),(6) было бы разумно запросить только эти пары, и самый простой способ - запросить их по отдельности.

Но в - третьих, поскольку три запроса структурно идентичны, отличаясь только значением свойства (если id следует рассматривать как свойство), вы можете упростить запрос, обобщив или обезличив то, что их отличает, т.е.используйте параметры.

START left = node({leftId}), right = node({rightId})
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel

parameters: {leftId:1, rightId:4}, {leftId:2, rightId:5}, {leftId:3, rightId:6}

Поскольку структура идентична, cypher может кэшировать план выполнения.Это обеспечивает хорошую производительность, а запрос является аккуратным, ремонтопригодным и может быть легко расширен, если позже вы захотите выполнить ту же операцию на других парах узлов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top