Создать граф из подмножества существующих узлов

У меня есть ориентированный граф Neo4j, содержащий 2 вида узлов: узлы с метками в наборе 1 и узлы с метками в наборе 2. Я хотел бы создавать новые ребра (нового типа) между узлами в наборе 1 всякий раз, когда есть направленный путь от узла Set 1 к другому узлу Set 1, который проходит только через узлы Set 2 (возможно, 0 таких узлов Set 2).

Вот пример набора данных:

CREATE (a:A {id:"a"})-[:CONN]->(t1:T {id:"t1"}),
   (t1)-[:CONN]->(b1:B {id:"b1"}),
   (b1)-[:CONN]->(t2:U {id:"t1"}),
   (t2)-[:CONN]->(c1:C {id:"c1"}),
   (c1)-[:CONN]->(t3:T {id:"t3"}),
   (t3)-[:CONN]->(d1:D {id:"d1"}),
   (t3)-[:CONN]->(d2:D {id:"d2"}),
   (d1)-[:CONN]->(t4:T {id:"t4"}),
   (d2)-[:CONN]->(t4),
   (t4)-[:CONN]->(e1:E {id:"e1"}),
   (t4)-[:CONN]->(e2:E {id:"e2"})

В этом примере A, B, C, D и E находятся в наборе 1, а T и U — в наборе 2, поэтому я хочу нарисовать новые ребра :AGG следующим образом:

MATCH (a:A {id:"a"}), (b1:B {id:"b1"}), (c1:C {id:"c1"}), (d1:D {id:"d1"}),
      (d2:D {id:"d2"}), (e1:E {id:"e1"}), (e2:E {id:"e2"})
CREATE (a)-[:AGG]->(b1),
   (b1)-[:AGG]->(c1),
   (c1)-[:AGG]->(d1),
   (c1)-[:AGG]->(d2),
   (d1)-[:AGG]->(e1),
   (d1)-[:AGG]->(e2),
   (d2)-[:AGG]->(e1),
   (d2)-[:AGG]->(e2)

Что касается ребер CONN, я знаю, что граф является DAG, поэтому мне не нужно беспокоиться о петлях.

Можно ли это сделать в Сайфере? Или кто-нибудь может предложить эффективный способ через интерфейсы Java (например, стратегию обхода)? Спасибо.


person Ken Williams    schedule 29.06.2015    source источник


Ответы (1)


Да, это можно сделать — это сложный запрос, поэтому вам, возможно, придется немного поиграть с ним, но вот с чего начать. Возможно, кто-то еще может прийти и улучшить это, но я думаю, что это должно выполнить большую часть основной логики.

MATCH p=(node1)-[*]-(node2)
WHERE ('A' in labels(node1) OR
       'B' in labels(node1) OR
       'C' in labels(node1) OR
       'D' in labels(node1) OR
       'E' in labels(node1)) 
      AND
      ('A' in labels(node2) OR
       'B' in labels(node2) OR
       'C' in labels(node2) OR
       'D' in labels(node2) OR
       'E' in labels(node2)) 
      AND
      (length(p) = 1 OR 
       all(intermedNode in 
           filter(n IN tail(nodes(p)) WHERE n <> last(nodes(p)))
           WHERE
           ('T' in labels(intermedNode) OR
            'U' in labels(intermedNode))))
WITH node1, node2
CREATE node1-[:MyNewNiftyEdge]->node2;

Объяснение:

  1. Мы ищем пути; первые два больших блока WHERE просто доказывают, что источник и цель пути должны быть в «Set1».
  2. Последняя часть блока WHERE делает все самое интересное. Пути длины 1 в порядке (ноль промежуточных узлов «Set2»). Но если есть промежуточные узлы, мы проверяем, все ли «внутренние» узлы являются «Set2». Бит filter с выражением tail просто отсекает от пути первый и последний узлы (мы уже знаем, что это node1 и node2). Затем выражение all настаивает на том, что если что-то находится посередине, то это должен быть узел Set2 (обозначенный буквой «T» или «U»).
  3. Наконец, с этими двумя совпадающими узлами мы создаем отличное новое отношение, соединяющее их напрямую.
person FrobberOfBits    schedule 29.06.2015
comment
Потрясающе, спасибо. Я также начал кодировать решение с интерфейсом Java, если это сработает, я тоже смогу опубликовать его здесь. - person Ken Williams; 30.06.2015