0

I am using Neo4j for my project.

In my graph DB I have 2 types of nodes:

  1. person
  2. fruit

person nodes may be connected with each other with relation friend person nodes are connected with the nodes of fruits if they like that fruit.

I want to find the set of group of 3 people who likes for example apple peach and orange and there is at least the path from one person to 3rd with relation "friend", or all 3 are friends.

Since I have started using neo4j just recently, I need Guru's help to come up with solution.

My though is:

find out the group of people who likes apple find out the group of people who likes peach find out the group od people who likes orange

from that 3 sets find out the existing node-rel-node-rel... path which starts in one of that sets goes through 2nd set end ends up in 3rd.

Could you please confirm if my approach is correct and optimal and is it possible to implement via Cypher or py2neo?

Couldn't find the way to share, but can paste the query here. If you paste it back to console.neo4j.org you will get a graph:

CREATE (Neo { name:'Neo' }),(Morpheus { name: 'Morpheus' }),(Trinity { name: 'Trinity' }),(Cypher { name: 'Cypher' }),(Apple { fruit: 'Apple' }),(Peach { fruit: 'Peach' }),(Banana { fruit:'Banana' }), root-[:ROOT]->Neo, Neo-[:KNOWS]->Morpheus, Neo-[:KNOWS]->Trinity, Morpheus-[:KNOWS]->Cypher, Neo-[:LIKES]->Peach, Trinity-[:LIKES]-Banana, Morpheus-[:LIKES]-Apple

Assuming that you see the model in mentioned website. So here I need to search people who like (Peach, Banana, Apple) as a Result I want to get Neo, Trinity and Morpheus, because Neo likes peach, Trinity likes banana and Morpheus likes apple and they are connected somehow (Neo knows both Morpheus and Trinity, even tho Trinity doesn't know Morpheus).

There gonna be 100K people in my DB and everyone connected with some people and with fruits they like. I want to proceed described search and get all possible matchings like Neo, Morpheus and Trinity. Hope this description much more clear.

danny
  • 65
  • 1
  • 8

1 Answers1

1

Try and see if this query meets your requirements. it retrieves groups of 3 persons, each of them likes one of the kind of fruit with a given name, and they are connected each other by one or two relationships [:KNOWS]. Not sure it would scale well.

Match p1:Person-[:LIKES]->f1:Fruit, p2:Person-[:LIKES]->f2:Fruit, p3:Person-[:LIKES]->f3:Fruit, path1=p1-[:KNOWS*1..2]-p2, path2=p2-[:KNOWS*1..2]-p3,path3=p1-[:KNOWS*1..2]-p3
Where f1.name = 'Apple' and f2.name='Peach' and f3.name = 'Banana' and all(n in nodes(path1) where n in [p1,p2,p3]) and all(n in nodes(path2) where n in [p1,p2,p3]) and all(n in nodes(path3) where n in [p1,p2,p3])
Return p1.name, p2.name, p3.name

Note: I have added a label ":Fruit" to each fruit node, and a label ":Person" to each person node.

Here is the console for the graph and the query,

http://console.neo4j.org/?id=fswj2b

Lisa Li
  • 2,562
  • 15
  • 11
  • Thanks for reply, will check how effective this approach. Maybe it makes sense to add node_auto_index on fruits? – danny Sep 30 '13 at 14:40
  • Yes, an index on the fruit name would be helpful to some extent. I have corrected a couple of typos in the query. so please make sure you check the updated query. – Lisa Li Sep 30 '13 at 14:50
  • I am trying the query on the example model with Neo Morpheus and Trinity, but it doesn't return anything (Query took 41 ms and returned no rows) – danny Sep 30 '13 at 14:59
  • Did you added the labels to the graph? I set up the console http://console.neo4j.org/?id=fswj2b for the query so that you can see the result there. – Lisa Li Sep 30 '13 at 15:24
  • Thank you! I didn't add labels. Thanks for the answer. Need to take a look at it more carefully to understand if it covers all cases and if that would work if Trinity liked for example peach and Neo banana. – danny Sep 30 '13 at 15:33
  • oh, I see why you didn't get any result. In your graph, the property on the fruit node is "fruit", and I use the property "name" on the fruit. So you just need to change the where clause to "where f1.fruit='Apple' and f2.fruit='Peach' and f3.fruit='Banana'". – Lisa Li Sep 30 '13 at 15:35
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38351/discussion-between-danny-and-lisa) – danny Sep 30 '13 at 15:36
  • http://console.neo4j.org/?id=j8os9c could you please take a look at this case? It returns result, but it shouldn't, coz Trinity and Neo are not friends for Cypher – danny Oct 04 '13 at 19:12
  • I see the problem, There should be another constraint for the person nodes, "p1-[:KNOWS*1..2]-p3". I updated the answer to fix the problem. – Lisa Li Oct 07 '13 at 16:13
  • that one also doesn't cover the case :( – danny Oct 08 '13 at 17:23
  • if we add "p1-[:KNOWS*1..2]-p3" constraint it appears that the query will return result if p1 is a friend of friend for p2, p2 is a friend of friend p3 and p3 is a friend of friend for p1. – danny Oct 08 '13 at 19:28
  • 1
    It seems getting quite complicated. I think the difficult is to express co occurrence constraints in the path. Anyway, I updated the query to ensure that any two points on the path are either connected directly or via the third point. i.e there shouldn't be any other points appearing on the path. – Lisa Li Oct 09 '13 at 01:37
  • Yes. Indeed! Could you please send me the link? I can't see where are your updates. Thanks – danny Oct 09 '13 at 06:46
  • I updated the query in the answer. Also the new console is here, http://console.neo4j.org/?id=lodahx – Lisa Li Oct 09 '13 at 16:35
  • Thanks Lisa, will try to expand it for using for more than 3 person cases – danny Oct 11 '13 at 19:32