1
votes

I have a graph database where there are user and interest nodes which are connected by IS_INTERESTED relationship. I want to find interests which are not selected by a user. I wrote this query and it is not working

OPTIONAL MATCH (u:User{userId : 1})-[r:IS_INTERESTED] -(i:Interest)
WHERE r is NULL
Return i.name as interest

According to answers to similar questions on SO (like this one), the above query is supposed to work.However,in this case it returns null. But when running the following query it works as expected:

MATCH (u:User{userId : 1}), (i:Interest)
WHERE NOT (u) -[:IS_INTERESTED] -(i)
return i.name as interest

The reason I don't want to run the above query is because Neo4j gives a warning:

This query builds a cartesian product between disconnected patterns.

If a part of a query contains multiple disconnected patterns, this will build a cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (i))

What am I doing wrong in the first query where I use OPTIONAL MATCH to find nonexistent relationships?

3

3 Answers

1
votes

1) MATCH is looking for the pattern as a whole, and if can not find it in its entirety - does not return anything.

2) I think that this query will be effective:

// Take all user interests
MATCH (u:User{userId: 1})-[r:IS_INTERESTED]-(i:Interest)
    WITH collect(i) as interests
    // Check what interests are not included
    MATCH (ni:Interest) WHERE NOT ni IN interests
RETURN ni.name
1
votes

When your OPTIONAL MATCH query does not find a match, then both r AND i must be NULL. After all, since there is no relationship, there is no way get the nodes that it points to.

0
votes

A WHERE directly after the OPTIONAL MATCH is pulled into the evaluation.

If you want to post-filter you have to use a WITH in between.

MATCH (u:User{userId : 1})
OPTIONAL MATCH (u)-[r:IS_INTERESTED] -(i:Interest)
WITH r,i
WHERE r is NULL
Return i.name as interest