2017-01-29 3 views
1

Как я могу подразумевать ограничения на путь переменной длины? неNeo4J Cypher: отфильтровать пути переменной длины по критериям

У меня есть все возможные пути из некоторого запроса start узла:

CREATE INDEX ON :NODE(id) 
MATCH all_paths_from_Start = (start:Person)-[:FRIENDSHIP*1..20]->(person:Person) 
WHERE start.id = 128 AND start.country <> "Uganda" 
RETURN paths; 

Нет Я хочу, чтобы отфильтровать все пути, которые имеют, по меньшей мере, два человека с одинаковыми country. Как я мог это сделать?

ответ

3

1) Получить массив стран на пути с возможными дубликатами: REDUCE

2) Удалить дубликаты и сравнить размеры массивов: UNWIND + COLLECT(DISTINCT...)

MATCH path = (start:Person)-[:FRIENDSHIP*1..20]->(person:Person) 
     WHERE start.id = 128 AND start.country <> "Uganda" 
WITH path, 
    REDUCE(acc=[], n IN NODES(path) | acc + n.country) AS countries 
    UNWIND countries AS country 
WITH path, 
    countries, COLLECT(DISTINCT country) AS distinctCountries 
    WHERE SIZE(countries) = SIZE(distinctCountries) 
RETURN path 

P.S. REDUCE можно заменить EXTRACT (благодаря Габора Szarnyas):

MATCH path = (start:Person)-[:FRIENDSHIP*1..20]->(person:Person) 
     WHERE start.id = 128 AND start.country <> "Uganda" 
WITH path, 
    EXTRACT(n IN NODES(path) | n.country) AS countries 
    UNWIND countries AS country 
WITH path, 
    countries, COLLECT(DISTINCT country) AS distinctCountries 
    WHERE SIZE(countries) = SIZE(distinctCountries) 
RETURN path 

P.P.S. Еще раз спасибо Gabor Szarnyas за дополнительную идею для упрощения запроса:

MATCH path = (start:Person)-[:FRIENDSHIP*1..20]->(person:Person) 
     WHERE start.id = 128 AND start.country <> "Uganda" 
WITH path 
    UNWIND NODES(path) AS person 
WITH path, 
    COLLECT(DISTINCT person.country) as distinctCountries 
    WHERE LENGTH(path) + 1 = SIZE(distinctCountries) 
RETURN path 
+0

Благодарим вас за ответ! Будет ли это лучшим выбором с точки зрения производительности? У меня будет очень большой набор данных с до миллиона узлов. Есть ли способ ускорить запрос? –

+1

@VolodymyrBakhmatiuk Самая тяжелая часть запроса - первая «MATCH»: «MATCH path = (start: Person) - [: FRIENDSHIP * 1..20] -> (person: Person) WHERE start.id = 128 И начать .country <> «Уганда». В настоящее время не совсем понятно, как его улучшить ... –

+1

@VolodymyrBakhmatiuk Тестирование пути самая простая часть ... –

2

Одно из решений, что я могу думать о том, чтобы получить nodes пути, и для каждого человека на пути, extract значения числа лиц из одной и тех же стран (которые мы определяем по filter ИНГАМ для та же страна. путь имеет человек из уникальных стран, если она имеет нулевой человек из той же страны, т.е. для всех людей, есть только один человек (человек сам/сама) из этой страны.

MATCH p = (start:Person {id: 128})-[:FRIENDSHIP*1..20]->(person:Person) 
WHERE start.country <> "Uganda" 
WITH p, nodes(p) AS persons 
WITH p, extract(p1 IN persons | size(filter(p2 IN persons WHERE p1.country = p2.country))) AS personsFromSameCountry 
WHERE length(filter(p3 IN personsFromSameCountry WHERE p3 > 1)) = 0 
RETURN p 

запрос синтаксически корректен, но я не тестировал его ни на какие данные.

Обратите внимание, что я переместил условие id = 128 на образец и укоротил переменную all_paths_from_Start как p.

 Смежные вопросы

  • Нет связанных вопросов^_^