Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
02-07-2022 11:57 PM
I am trying to work on neo4j for the first time. I have written the following:
LOAD CSV WITH HEADERS FROM "file:///restaurant_data.csv" AS data
MERGE(n1:Customer{Name:data.Name, Latitude:toFloat(data.Latitude),Longitude:toFloat(data.Longitude)})
MERGE(n2:Orders{OrderId:data.Order_ID,OrderTimestamp:data.Order_ts,FoodName:data.Food_Item})
MERGE(n3:Restaurant{RestaurantName:data.Restaurant, RestLat:toFloat(data.Rest_lat), RestLong:toFloat(data.Rest_long)})
MERGE (n1)-[r1:PLACES_ORDER]->(n2)
MERGE (n2)-[r2:BELONGS_TO]->(n3)
MERGE (n3)-[r3:SERVES]->(n2)
RETURN *;
I want to get a Customers last 5 orders by order timestamp desc and then give him recommendations of restaurants serving that food. I also want to give him recommendations based on his location. the distance between him and restaurant should be less than 5kms.
I have written the following query:
MATCH(n1:Customer{Name:"Angy"})
MATCH(n1)-[:PLACES_ORDER]->(n2:Orders)<-[:SERVES]-(rec:Restaurant)
RETURN n2.FoodName, n2.OrderTimestamp, n3.RestaurantName
ORDER BY n2.OrderTimestamp
LIMIT 5
which successfully gave me last 5 orders.
then I wrote this one however it gives me "no matches, no records"
MATCH(n1:Customer{Name:"Angy"})-[:PLACES_ORDER]->(n2:Orders)<-[:SERVES]-(:Restaurant)
WITH n2 ORDER BY n2.OrderTimestamp DESC LIMIT 5
WITH collect(distinct n2) as orders
MATCH (r:Restaurant) WHERE ALL(order in orders WHERE EXISTS((r)-[:SERVES]->(order)))
RETURN distinct r.RestaurantName
How do I achieve what I want? I have been spending a lot of hours but unable to get anything. Please help.
02-08-2022 06:31 AM
This should work:
MATCH(n1:Customer{Name:"Angy"})-[:PLACES_ORDER]->(n2:Orders)
WITH n2 ORDER BY n2.OrderTimestamp DESC LIMIT 5
MATCH (n2)<-[:SERVES]-(:Restaurant)
RETURN distinct r.RestaurantName
You may want to consider a different domain model. Instead of storying the food information in the order, create a Item node for each Food item. Then link the order to the food item, which is linked to the restaurant.
(:Customer)-[:PLACES_ORDER]->(:Order)-[:CONTAINS_ITEM]->(:Item)<-[:SERVES]-(:Restaurant)
This model allows an order to have multiple items and an item can be served by multiple restaurants.
02-08-2022 07:10 AM
Hi This is working but this is not what I want. From your query I got restaurants who served Angy. I want to get restuarants which have those food items which Angy has ordered so that Angy. basically reccomendations for Angy. How to get that?
02-08-2022 07:48 AM
Ok, you need to get the foods from the person's last five orders, and look for restaurants that serve those foods. Try the following:
MATCH(:Customer{Name:"Angy"})-[:PLACES_ORDER]->(o:Orders)
WITH o ORDER BY o.OrderTimestamp DESC LIMIT 5
WITH [o.FoodName] as foods
MATCH (:Restaurant)-[:SERVES]->(n:Orders)
WHERE (n.FoodName in foods)
RETURN distinct r.RestaurantName
You may want to consider the following data model as an alternative:
(:Customer)-[:PLACES_ORDER]->(:Orders)-[:CONTAINS_ITEM]->(:Item)<-[:SERVES]-(:Restaurant)
In this case, the query would look something like:
MATCH(:Customer{Name:"Angy"})-[:PLACES_ORDER]->(o:Orders)
WITH o ORDER BY o.OrderTimestamp DESC LIMIT 5
MATCH (o)-[:CONTAINS_ITEM]->(:Item)<-[:SERVES]-(r:Restaurant)
RETURN DISTINCT r.RestaurantName
02-08-2022 10:20 AM
Ok thank you so much this is working. I am also going to try the other data model you suggest. Can you also suggest how can I calculate Location based on my Lat and Long coordinates and choose restaurants which are nearest to customer's Lat and Long?
02-08-2022 12:01 PM
I am thinking something like this, where $myLongitude and $myLatitude are parameters passed to the query. I don't have experience using the point/distance methods, but I assume they work as advertised. I don't have test data to test the syntax or results either. Let me know if there are issues and we can try to figure them out.
MATCH(:Customer{Name:"Angy"})-[:PLACES_ORDER]->(o:Orders)
WITH o ORDER BY o.OrderTimestamp DESC LIMIT 5
WITH [o.FoodName] as foods, point({latitude: $myLatitude, longitude: $myLongitude}) as myPoint
MATCH (r:Restaurant)-[:SERVES]->(n:Orders)
WHERE (n.FoodName in foods)
WITH r.RestaurantName as restaurant, point.distance(point({latitude: r.RestLat, longitude: r.RestLong}), myPoint) as distance
ORDER BY distance DESC
LIMIT 3
RETURN restaurant, distance
02-09-2022 07:34 AM
Hi Thank you for your query: I could find the distance between my customer and a restaurant by this
MATCH(c:Customer)-[:PLACES_ORDER]->(o:Orders)-[:BELONGS_TO]->(r:Restaurant)
MATCH(o:Orders)-[:BELONGS_TO]->(r:Restaurant)
WITH point({longitude: c.Longitude, latitude: c.Latitude}) AS trainPoint, point({longitude: r.RestLong, latitude: r.RestLat}) AS officePoint
RETURN round(point.distance(trainPoint, officePoint)) AS travelDistance
ORDER BY travelDistance DESC
How do I integrate this in my final search query for recommendaitons?
MATCH(c:Customer{Name:"Ania"})-[:PLACES_ORDER]->(o:Orders)
WITH o ORDER BY o.OrderTimestamp DESC LIMIT 5
WITH [o.FoodName] as foods
MATCH (r:Restaurant)<-[:BELONGS_TO]-(o:Orders{FoodName:"Pommes"})
WHERE (o.FoodName in foods) AND NOT (:Customer{Name:"Angy"})-[:PLACES_ORDER]->(o:Orders)-[:BELONGS_TO]->(r:Restaurant)
RETURN distinct r.RestaurantName,foods
02-09-2022 08:57 AM
Does your final query give you the results you want? The second match basically restricts your search to only the food "Pommes" and only if "Ania" ordered it within her last 5 orders, and "Angy" could never of ordered "Pommes" as well. If that is true, you will get the Restaurants that serve "Pommes" and a list of the last 5 foods "Ania" ordered.
02-09-2022 09:01 AM
yes sorry thats a typo. Its ANIA on both places. and yes this is working. Now i want to integrate my distance query into this.
02-09-2022 09:03 AM
Why are you restricting the food to "Pommes" in the second match?
I also provided a solution using the distance in a few messages back.
02-09-2022 09:10 AM
yes yes , i was just trying to customise .. suppose a user wants to only know where he can find "pommes"... do you know how to integrate that distance query to my main query? and find restaurants as per the distance?
02-09-2022 09:16 AM
I suggest you build two separate queries, as these seem like two separate uses cases. A query to find restaurants that sell "Pommes" would be:
match (o:Orders)-[:BELONGS_TO]->(r:Restaurant)
where o.FoodName = "Pommes"
return r.RestaurantName
The issue with your data model is that someone has to order an item for the food to be introduced into your model. Typically, the food would be in its own entity, and the restaurant and orders would refer to it.
All the sessions of the conference are now available online