2015-04-03 7 views
2

Я пишу запрос Cypher в Neo4j 2.0.4, который пытается получить общее количество входящих и исходящих отношений для выбранного узла. Я могу сделать это легко, когда я использую только этот запрос один-узел-в-времени, например, так:Использование совпадения с несколькими пунктами приводит к нечетным результатам

MATCH (g1:someIndex{name:"name1"}) 
MATCH g1-[r1]-() 
RETURN count(r1); 
//Returns 305 

MATCH (g2:someIndex{name:"name2"}) 
MATCH g2-[r2]-() 
RETURN count(r2); 
//Returns 2334 

Но когда я пытаюсь выполнить запрос с 2-мя узлами вместе (т.е. получить общее количество отношения для g1 и g2), я, кажется, получаю причудливый результат.

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 
//Returns 1423740 

По какой-то причине это число намного больше, чем общее количество 305 + 2334.

Похоже, что другие пользователи Neo4j столкнулись странные вопросы, при использовании нескольких MATCH положений, так что я прочитал объяснение Майкла Хунгера на https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ, который консультировал пользователей Neo4j к трубе результаты одного матча с использованием WITH, чтобы избежать «идентификатор уникальности» , Однако, когда я запускаю следующий запрос, он просто раз из:

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"}) 
MATCH g1-[r1]-() 
WITH r1 
MATCH g2-[r2]-() 
RETURN count(r1)+count(r2); 

Я подозреваю, что этот запрос не возвращается, потому что есть много записей, возвращаемый r1. В этом случае, как бы я мог использовать запрос «get-number-of-relationship» на двух узлах? Я просто использую какой-то неправильный синтаксис или есть какая-то фундаментальная проблема с логикой моего запроса «2 узла за раз»?

ответ

3

Ваша первая проблема заключается в том, что вы возвращаете декартово произведение, когда вы делаете это:

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 

Если есть 305 экземпляров r1 и 2334 экземпляров r2, вы возвращающиеся (305 * 2334) = = 711870 строк, а потому, что вы суммируя это (count(r1)+count(r2)) вы получаете в общей сложности 711870 + 711870 == 1423740.

Ваша вторая проблема заключается в том, что вы не перенесение g2 в предложении этого запроса WITH:

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"}) 
MATCH g1-[r1]-() 
WITH r1 
MATCH g2-[r2]-() 
RETURN count(r1)+count(r2); 

Вы матч на g2 в первом MATCH пункте, но оставить его позади, когда вы носите только над r1 в пункте WITH в строке 3. Затем, в строке 4, когда вы подходите на g2-[r2]-() вы соответствия буквально все в вашем графике, потому что g2 был несвязан.

Позвольте мне пройти через решение с набором данных для фильма, который поставляется с браузером Neo4j, поскольку вы не предоставили образцы данных. Предположим, я хочу получить общее количество отношений, связанных с Томом Хэнксом и Хьюго Уивинг.

Как отдельные запросы:

MATCH (:Person {name:'Tom Hanks'})-[r]-() 
RETURN COUNT(r) 

=> 13

MATCH (:Person {name:'Hugo Weaving'})-[r]-() 
RETURN COUNT(r) 

=> 5

Если я пытаюсь сделать это по-своему, я буду получать (13 * 5) * 2 == 90, что является неправильным:

MATCH (:Person {name:'Tom Hanks'})-[r1]-(), 
     (:Person {name:'Hugo Weaving'})-[r2]-() 
RETURN COUNT(r1) + COUNT(r2) 

=> 90

Опять же, это происходит потому, что я соответствовал на всех комбинаций r1 и r2, из которых есть 65 (13 * 5 == 65) и затем суммируются, чтобы это прийти в общей сложности 90 (65 + 65 = 90).

Решение состоит в том, чтобы использовать DISTINCT:

MATCH (:Person {name:'Tom Hanks'})-[r1]-(), 
     (:Person {name:'Hugo Weaving'})-[r2]-() 
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2) 

=> 18

Очевидно, что модификатор DISTINCT только подсчитывает различные экземпляры каждого объекта.

Вы также можете сделать это с WITH, если вы хотите:

MATCH (:Person {name:'Tom Hanks'})-[r]-() 
WITH COUNT(r) AS r1 
MATCH (:Person {name:'Hugo Weaving'})-[r]-() 
RETURN r1 + COUNT(r) 

=> 18

TL; DR - Остерегайтесь декартовых произведений. DISTINCT ваш друг:

MATCH (:someIndex{name:"name1"})-[r1]-(), 
     (:someIndex{name:"name2"})-[r2]-() 
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2); 
+0

Спасибо Николь! Я не знал, что мой текущий запрос использует кросс-продукт; теперь это намного больше. –

3

Взрыв результатов вы видите можно легко объяснить:

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 
//Returns 1423740 

В 2-й линии каждой комбинации каких-либо отношений с g1 сочетается с любым соотношением g2 , это объясняет число с 1423740 = 305 * 2334 * 2. Итак, вы оцениваете в основном кросс-продукт здесь.

Правильный способ вычисления суммы всех отношений для name1 и name2 является:

MATCH (g:someIndex)-[r]-() 
WHERE g.name in ["name1", "name2"] 
RETURN count(r) 
+0

Спасибо, Стефан! Это имеет смысл сейчас. +1 –

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