1
votes

I'm trying to query Book nodes for recommendation by Cypher.
I want to recommend A:Book and C:Book for A:User.
i'm sorry I need some graph to explain this question, but I could't up graph image because my lepletion lacks for upload function.
I wrote query below.

match (u1:User{uid:'1003'})-->(o1:Order)-->(b1:Book)<--(o2:Order)
      <--(u2:User)-->(o3:Order)-->(b2:Book)
return b2

This query return all Books(A,B,C,D) dispite cypher's Uniqueness.
I expect to only return A:Book and C:Book.
Is this behavior Neo4j' specification?
How do I get expected return? Thanks, everyone.

environment: Neo4j ver.v2.0.0-RC1 Using Neo4j Server with REST API

1
You can share a sample graph by including a create statement that would generate said graph, or by creating it in Neo4j console and putting the link in your question. Here is an example of the latter: console.neo4j.org/r/fnnz6bjjaderberg
Thank you for you response immediately. I didn't know this convenient site. I'll try to share some graph soon.Michael
My graph is this link. console.neo4j.org/?id=e242cm User can buy a book at one time. it means order can contain only one book.Michael

1 Answers

1
votes

Without the sample graph its hard to say why you get something back when you expected something else. You can share a sample graph by including a create statement that would generate said graph, or by creating it in Neo4j console and putting the link in your question. Here is an example of the latter: console.neo4j.org/r/fnnz6b

In the meantime, you probably want to declare the type of the relationships in your pattern. If a :User has more than one type of outgoing relationships you will be excluding those other paths based on the labels of the nodes on the other end, which is much less efficient than to only traverse the right relationships to begin with.

To my mind its not clear whether (u:User)-->(o:Order)-->(b:Book) means that a user has one or more orders, and each order consists of one or more books; or if it means only that a user ordered a book. If you can share a sample, hopefully that will be clear too.

Edit:
Great, so looking at the graph: You get B and D back because others who bought B also bought D, and others who bought D also bought B, which is your criterion for recommendation. You can add a filter in the WHERE clause to exclude those books that the user has already bought, something like

WHERE NOT (u1)-[:BUY]->()-[:CONTAINS]->(b2)

This will give you A, C, C back, since there are two matching paths to C. It's probably not important to get two result items for C, so you can either limit the return to give only distinct values

RETURN DISTINCT(b2)

or group the return values by counting the matching paths for each result as a 'recommendation score'

RETURN b2, COUNT(b2) as score

Also, if each order only [CONTAINS] one book, you could try modelling without order, just (:User)-[:BOUGHT]->(:Book).