Отфильтруйте отношения в Neo4j, используя даты начала и окончания - PullRequest
0 голосов
/ 05 октября 2018

У меня есть графовая модель -

(p:Person)-[r:LINK {startDate: timestamp, endDate: timestamp}]->(c:Company)

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

Свойство endDate является необязательным и будет присутствовать только после того, как человек покинул компанию.

Я пытаюсь отобразить сеть соединенийи может успешно возвратить все связанные узлы от человека, используя следующий запрос шифра (это отобразит 2 уровня связи людей) -

MATCH (p:Person {id:<id>})-[r:LINK*0..4]-(l) RETURN *

Что мне теперь нужно сделать, это отфильтровать отношения, в которых отношения совпадаютвременные рамки, например, Лицо 1 работало в компании А в период с 01.01.2000 г. по 31.12.2002 г.Человек 2 работал в компании A с 01.01.2001 по 31.06.2001.Лицо 3 работало в компании А в период с 01.01.2005 г. и по-прежнему в компании А. Результаты для лица 1 должны включать лицо 2, но не лицо 3.

Эту же логику необходимо применять ко всем уровнямграфик (мы разрешаем пользователю отображать 3 уровня соединений) и относится к родительскому узлу на каждом уровне, т. е. при отображении уровня 2 даты для лица 2 и лица 3 должны использоваться для фильтрации их соответствующих отношений.

По сути, мы пытаемся сделать что-то похожее на соединения LinkedIn, но фильтровать, основываясь на людях, работающих в компаниях одновременно.

Я пытался использовать функцию REDUCE, но не могу заставить работать логикудля дополнительной даты окончания - кто-нибудь может посоветовать, как отфильтровать отношения по датам начала и окончания?

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Оказывается, есть 4 способа, которыми диапазоны дат могут перекрываться, но только 2, в которых они не перекрываются (человек 1 заканчивается до того, как человек 2 начинает, или человек 2 заканчивается, пока человек 1 не начинает), поэтому намного прощеубедитесь, что ни одно из этих условий не перекрывается.

В случае уровня 1 этот запрос должен выполнить свою задачу:

MATCH (start:Person{id:1})-[r1:LINK]->(c)<-[r2:LINK]-(suggest)
WHERE NOT ((r1.endDate IS NOT NULL and r1.endDate < r2.startDate) 
        OR (r2.endDate IS NOT NULL and r2.endDate < r1.startDate))
RETURN suggest

Сложная часть применяет это к нескольким уровням.

Хотя мы могли бы создать один запрос Cypher для его динамической обработки, оценка отношений будет происходить только после расширения, а не во время, поэтому он может быть не самым эффективным:

MATCH path = (start:Person{id:1})-[:LINK*..6]-(suggest:Person)
WITH path, start, suggest, apoc.coll.pairsMin(relationships(path)) as pairs
WITH path, start, suggest, [index in range(0, size(pairs)-1) WHERE index % 2 = 0 | pairs[index]] as pairs
WHERE none(pair in pairs WHERE (pair[0].endDate IS NOT NULL AND pair[0].endDate < pair[1].startDate) 
                          OR (pair[1].endDate IS NOT NULL AND pair[1].endDate < pair[0].startDate))
RETURN suggest

Некоторые из основных моментов здесь ...

Мы используем apoc.coll.pairsMin() из процедур APOC, чтобы получить пары смежных отношений из коллекции отношений в каждом пути, но нас интересует только четноепронумерованные записи (два отношения от людей, работающих в одной и той же компании), потому что нечетные пары соответствуют отношениям одного и того же человека, идущего в две разные компании.

Итак, если мы выполняем по этому шаблону:

MATCH path = (start:Person)-[r1:LINK]->(c1)<-[r2:LINK]-(person2)-[r3:LINK]->(c2)<-[r4:LINK]-(person3)

apoc.coll.pairsMin(relationships(path)) вернет [[r1, r2], [r2,r3], [r3,r4]], и, как вы видите, отношения, которые мы должны рассмотреть, связывают двух человек с компанией, поэтому индексы 0 и 2в списке пар.

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

0 голосов
/ 06 октября 2018

Как-то так должно работать:

MATCH path=(p:Person {id: $id})-[r:LINK*..4]-(l)
WHERE ALL(x IN NODES(path)[1..] WHERE x.startDate <= p.endDate AND x.endDate >= p.startDate)
RETURN path;

Допущения:

  • Значение id основного заинтересованного лица предоставляется $id параметр .
  • Вы хотите, чтобы шаблон отношения переменной длины имел нижнюю границу 1 (по умолчанию).Если вы использовали 0 для нижней границы, то в результате вы также получите интересующего вас главного человека - что, вероятно, не то, что вам нужно.
  • startDate и endDate имеют значения, которые подходятдля сравнения используйте операторы сравнения
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...