Answering an Stackoverflow Question.
I am learning Neo4j and decided to take one of the sample queries and add a twist to it. I took this example http://docs.neo4j.org/chunked/stable/cypher-cookbook-co-favorited-places.html and wanted to say what if there was an additional attribute that you could use to filter the results by. My test I put together was to have tags in the graph as well and then I wanted to search by overlapped favorites desc then by overlapping tags desc.
Here is the sample data I am using:
CREATE (Keanu:Person {name:'Keanu Reeves', born:1964})
CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967})
CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961})
CREATE (Hugo:Person {name:'Hugo Weaving', born:1960})
CREATE (UserBart:User {username:'bart' })
CREATE (UserHomer:User {username:'homer' })
CREATE (UserMarge:User {username:'marge' })
CREATE (Male:Tag {name:'male' })
CREATE (Female:Tag {name:'female' })
CREATE (BadHair:Tag {name:'badhair' })
CREATE
(UserBart)-[:FAVORITE]->(Keanu),
(UserBart)-[:FAVORITE]->(Laurence),
(UserBart)-[:FAVORITE]->(Carrie),
(UserHomer)-[:FAVORITE]->(Carrie),
(UserHomer)-[:FAVORITE]->(Hugo),
(UserMarge)-[:FAVORITE]->(Keanu),
(UserMarge)-[:FAVORITE]->(Laurence),
(UserMarge)-[:FAVORITE]->(Carrie),
(Male)-[:TAGGED]->(Keanu),
(Male)-[:TAGGED]->(Laurence),
(Male)-[:TAGGED]->(Hugo),
(Female)-[:TAGGED]->(Carrie),
(BadHair)-[:TAGGED]->(Keanu),
(BadHair)-[:TAGGED]->(Laurence)
I would like to answer this question: for all the people who favorited Keanu Reeves, who else have they favorited and if there is a tie breaker show the person with the most related tags first. With the sample data, there are two people that were favorited by users who also favorited Keanu: Carrie and Laurence. Carrie has no overlapping tags with Keanu while Laurence has two overlapping tags. I would like to get the following results:
Name SharedFavCount OverlapTagCount Laurence 2 2 Carrie 2 0
I have tried a bunch of different cyphers with different combination and haven’t been able to crack it.
The cypher I find the oddest - I probably don’t fully understand cyphers yet - is this one where I am explicitly saying I don’t want Keanu in the results but alas he appears in the results. Here is that cypher along with the results.
MATCH (anchor:Person)<-[:FAVORITE]-(u:User)-[:FAVORITE]->(similiar:Person)
OPTIONAL MATCH (anchor)<-[:TAGGED]-(t:Tag)-[:TAGGED]->(similiar2:Person)
WHERE anchor.name = 'Keanu Reeves'
AND similiar.name <> 'Keanu Reeves'
AND similiar.name = similiar2.name
return similiar.name, count(DISTINCT u.username), count(DISTINCT t.name)
and the results for that cypher:
Name SharedFavCount OverlapTagCount Carrie 3 0 Hugo 1 0 Laurence 2 2 Keanu 2 0
Any ideas how I can get the desired results?
Your WHERE filtering for "Keanu Reeves" is applied to the wrong match, move it upwards behind the MATCH clause. And add an ORDER BY for your tie-break rule.
You can also simplify your query, you don’t need the additional constraints, rather reuse the similiar identifier. Keanu Reeves cannot appear as similiar as the FAVORITE relationship pointing to him is already used in the path.
MATCH (anchor:Person)<-[:FAVORITE]-(u:User)-[:FAVORITE]->(similiar:Person)
WHERE anchor.name = 'Keanu Reeves'
OPTIONAL
MATCH (anchor)<-[:TAGGED]-(t:Tag)-[:TAGGED]->(similiar)
RETURN similiar.name, count(DISTINCT u.username) as favs, count(DISTINCT t.name) as tags
ORDER BY favs DESC, tags DESC
Returning the same results:
But it’s not what you want.