2014-11-28 4 views
1

Предположим, у меня есть два типа узлов, Person и Competency. Они связаны соотношением KNOWS. Например:Выберите узлы, которые имеют все отношения в Neo4j

(:Person {id: 'thiago'})-[:KNOWS]->(:Competency {id: 'neo4j'}) 

Как запросить эту схему, чтобы выяснить все Person, который знает все узлы набора Competency?

Предположим, что мне нужно найти все Person, который знает «Java» и «Haskell», и я заинтересован только в узлах, которые знают все из перечисленных Competency узлов.

Я попробовал этот запрос:

match (p:Person)-[:KNOWS]->(c:Competency) where c.id in ['java','haskell'] return p.id; 

Но я вернусь список всех Person, который знает, либо «Java» или «Haskell» и дублирующиеся записи для тех, кто знает, как.

Добавление count(c) в конце запроса устраняет дубликаты:

match (p:Person)-[:KNOWS]->(c:Competency) where c.id in ['java','haskell'] return p.id, count(c); 

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

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

match (p:Person)-[:KNOWS]->(:Competency {id:'haskell'}) 
match (p)-[:KNOWS]->(:Competency {id:'java'}) 
return p.id; 

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

ответ

2
with ['java','haskell'] as skills 
match (p:Person)-[:KNOWS]->(c:Competency) 
where c.id in skills 
with p.id, count(*) as c1 ,size(skills) as c2 
where c1 = c2 
return p.id 
1

Одна вещь, которую вы можете сделать, чтобы подсчитать число всех навыков, то найти пользователей, которые имеют количество навыков отношений равно навыков подсчитывать:

MATCH (n:Skill) WITH count(n) as skillMax 
MATCH (u:Person)-[:HAS]->(s:Skill) 
WITH u, count(s) as skillsCount, skillMax 
WHERE skillsCount = skillMax 
RETURN u, skillsCount 

Крис

1

тестировался, но это может сделать трюк:

match (p:Person)-[:KNOWS]->(c:Competency) 
with p, collect(c.id) as cs 
where all(x in ['java', 'haskell'] where x in cs) 
return p.id; 
1

Как об этом ...

with ['java','haskell'] as comp_col 
match (p:Person)-[:KNOWS]->(c:Competency) 
where c.name in comp_col 
with comp_col 
, p 
, count(*) as total 
where total = length(comp_col) 
return p.name, total 
  1. Поместите компетенции в коллекцию.
  2. Совпадение все люди, которые имеют либо из этих компетенций
  3. Получить количество compentencies от человека, где они имеют такое же количество, как и в коллекции компетентностного с самого начала

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

Было бы интересно посмотреть, что говорит анализатор плана в области из разных подходов.

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