Skip to content

Instantly share code, notes, and snippets.

@gromajus
Last active January 11, 2016 15:55
Show Gist options
  • Save gromajus/8731452 to your computer and use it in GitHub Desktop.
Save gromajus/8731452 to your computer and use it in GitHub Desktop.

FOOD RECIPES RECOMMENDATION GRAPH

Inspiration

Currently, more and more people suffer from different kinds of food allergies and intolerances. They have problem if they want to go to random restaurant with their friends as there might be almost nothing they can eat there or they may eat something that can cause health problems. Cooking by themeselves is not a trivial thing neither. On one hand the Internet is full of various recipes but if it comes to choosing something tasty, it occurs that it requires ingredients you are alergic to. In order to help people to find the food recipes that they can probably like and are able to try, the RECIPES RECOMMENDATION GRAPH has been created (just the following concept for the moment). This model organizes collection of food recipes and combines it with standard social network of people. It could be used by the owners/ creator of portals with food recipes providing the recommendation functionality.

Data Model

The following model has been designed for the above problem implementation.

62f589ad

It consists of three domains:

  • Person (attributes: name), e.g. Bob

  • Recipe (attributes: name, formula, type - e.g. dessert, main course), e.g. fried potatoes

  • Product (attributes: name), e.g. potato

The following facts can be observed:

  • Person IS_FRIEND_OF another Person, e.g. Bob IS_FRIEND_OF Alice

  • Person IS_ALLERGIC_TO specific Product, e.g. Bob IS_ALLERGIC_TO potato

  • Person LOVES specific Product, e.g. Bob loves pasta

  • Person HATES specific Product, e.g. Bob hates rice

  • Recipe HAS_INGREDIENT Product, e.g. friend potatoes HAS_INGREDIENT potato

A query console

This console allows you to play with the described model - you can ask Cypher queries to check it. It also desplays the result of last executed Cypher query from the list presented below.

Graph data upload

Firtly, the test data is added to the database.

The initial database has been populated with the following information:

People:

  • Michael who has two friends: Cathy and Mateo. Michael is allergic to cow milk, gluten and wheat most of all. He loves chocolate but hates bananas.

  • Cathy who is friends with Michael. She is allergic to nuts and wheat. She loves chocolate as Michael.

  • Mateo who is friends with Michael.

  • Peter who has two friends: John and Mary. He is allergic to gluten.

  • John who is friends with Peter. He is allergic to gluten.

  • Mary who is friends with Peter. She is allergic to cow milk and apples.

Recipes for:

  • desserts:

    • chocolate soup made of passion fruit, coconut milk, chocolate and sugar

    • chocolate cake made of chocolate, wheat, sugar and eggs

    • strawberry icecream made of water, sugar and strawberries

  • soups:

    • tomato soup made of tomatoes, water and rice

  • sauces:

    • tomato sauce made of tomatoes, water and onion

//Person
CREATE (michael:Person{name:'Michael'}),
       (cathy:Person{name:'Cathy'}),
       (mateo:Person{name:'Mateo'}),
       (peter:Person{name:'Peter'}),
       (john:Person{name:'John'}),
       (mary:Person{name:'Mary'})

//Product
CREATE (chocolate:Product{name:'chocolate'}),
       (cow_milk:Product{name:'cow_milk'}),
       (gluten:Product{name:'gluten'}),
       (nuts:Product{name:'nuts'}),
       (wheat:Product{name:'wheat'}),
       (passion_fruit:Product{name:'passion fruit'}),
       (coconut_milk:Product{name:'coconut milk'}),
       (sugar:Product{name:'sugar'}),
       (egg:Product{name:'egg'}),
       (apple:Product{name:'apple'}),
       (tomato:Product{name:'tomato'}),
       (water:Product{name:'water'}),
       (rice:Product{name:'rice'}),
       (banana:Product{name:'banana'}),
       (strawberry:Product{name:'strawberry'}),
       (onion:Product{name:'onion'})

//Recipe
CREATE (chocolate_soup:Recipe{name:'Chocolate soup', type:'dessert', formula:'formula for the Chocolate soup'}),
       (chocolate_cake:Recipe{name:'Chocolate cake', type:'dessert', formula:'formula for the Chocolate cake'}),
       (tomato_soup:Recipe{name:'Tomato soup', type:'starter', formula:'formula for the Tomato soup'}),
       (strawberry_icecream:Recipe{name:'Strawberry icecream', type:'dessert', formula:'formula for the Strawberry icecream'}),
       (tomato_sauce:Recipe{name:'Tomato sauce', type:'sauce', formula:'formula for the Tomato sauce'})

//Friendship
CREATE michael-[:IS_FRIEND_OF]->cathy,
       cathy-[:IS_FRIEND_OF]->michael,
       michael-[:IS_FRIEND_OF]->mateo,
       mateo-[:IS_FRIEND_OF]->michael,
       peter-[:IS_FRIEND_OF]->john,
       john-[:IS_FRIEND_OF]->peter,
       peter-[:IS_FRIEND_OF]->mary,
       mary-[:IS_FRIEND_OF]->peter


//Allergies and preferences
CREATE michael-[:IS_ALLERGIC_TO]->cow_milk,
       michael-[:IS_ALLERGIC_TO]->gluten,
       michael-[:IS_ALLERGIC_TO]->wheat,
       michael-[:LOVES]->chocolate,
       michael-[:HATES]->banana,

       cathy-[:IS_ALLERGIC_TO]->nuts,
       cathy-[:IS_ALLERGIC_TO]->wheat,
       cathy-[:LOVES]->chocolate,

       peter-[:IS_ALLERGIC_TO]->gluten,
       john-[:IS_ALLERGIC_TO]->gluten,
       mary-[:IS_ALLERGIC_TO]->cow_milk,
       mary-[:IS_ALLERGIC_TO]->apple

//Recipes made of Products
CREATE chocolate_soup-[:HAS_INGREDIENT]->passion_fruit,
       chocolate_soup-[:HAS_INGREDIENT]->coconut_milk,
       chocolate_soup-[:HAS_INGREDIENT]->chocolate,
       chocolate_soup-[:HAS_INGREDIENT]->sugar,
       chocolate_cake-[:HAS_INGREDIENT]->chocolate,
       chocolate_cake-[:HAS_INGREDIENT]->wheat,
       chocolate_cake-[:HAS_INGREDIENT]->sugar,
       chocolate_cake-[:HAS_INGREDIENT]->egg,
       strawberry_icecream-[:HAS_INGREDIENT]->water,
       strawberry_icecream-[:HAS_INGREDIENT]->sugar,
       strawberry_icecream-[:HAS_INGREDIENT]->strawberry,
       tomato_soup-[:HAS_INGREDIENT]->tomato,
       tomato_soup-[:HAS_INGREDIENT]->water,
       tomato_soup-[:HAS_INGREDIENT]->rice,
       tomato_sauce-[:HAS_INGREDIENT]->tomato,
       tomato_sauce-[:HAS_INGREDIENT]->water,
       tomato_sauce-[:HAS_INGREDIENT]->onion

Use cases

Two basic applications of the model has been identified and specific questions asked (Cypher queries below) to solve the problems:

  • Statistics:

    • What are the most common food allergies?

    • What products are the most often used in desserts?

  • Recommendations:

    • I feel like eating particular product, what can I cook?

    • I have some products, what can I cook with these products (taking into account my preferences)?

    • My friends are coming, what can I cook to please them all?

What are the most common food allergies?

MATCH ()-[:IS_ALLERGIC_TO]->(r:Product)
WITH COUNT(*) AS total
MATCH ()-[a:IS_ALLERGIC_TO]->(r:Product)
WITH total, r.name AS name, count(a) AS each_sum
RETURN name,(each_sum*100.0)/(total)*1.0 AS percentage
ORDER BY percentage DESC , name

What products are the most often used in desserts?

MATCH (r:Recipe{type:"dessert"})-[i:HAS_INGREDIENT]->(p:Product)
WITH p.name as name, count(i) as sum
RETURN name
ORDER BY sum desc

I (Michael) feel like eating a dessert, what can I cook?

//checking what Michael should not eat
MATCH (m:Person { name:"Michael" })-[:IS_ALLERGIC_TO|HATES]->(bad_food:Product)
WITH m, bad_food

//checking the recipes for desserts that Michael should not eat
MATCH (r:Recipe { type:"dessert" })-[:HAS_INGREDIENT]->(p:Product)
WITH m, bad_food, p, r
WHERE p IN bad_food
WITH m, bad_food, r AS bad_recipe

//checking the recipes for dessert that Michael can eat
MATCH (r:Recipe { type:"dessert" })-[:HAS_INGREDIENT]->(p:Product)
WITH m, bad_recipe, r
WHERE NOT (r IN bad_recipe)
WITH r AS rec_dessert, m

//checking the favourite ingredients that the allowed recipe can contain
MATCH (m)-[:LOVES]->(favorite:Product)<-[HAS_INGREDIENT]-(rec_dessert)
RETURN DISTINCT rec_dessert.name as recommended_dessert

I (Michael) feel like cooking something of tomatoes and rice, what can I cook with these products (taking into account my preferences)?

//checking products Michael should not eat
MATCH (m:Person { name:"Michael" })-[:IS_ALLERGIC_TO|HATES]->(bad_food:Product)
WITH bad_food

//checking the recipes that Michael should not eat
MATCH (r:Recipe)-[:HAS_INGREDIENT]->(p:Product)
WITH bad_food, p, r
WHERE p IN bad_food
WITH bad_food, r AS bad_recipe

//checking if 2 ingredients match somewhere and Michael can eat this food
MATCH (tomato:Product{ name:"tomato" })<-[:HAS_INGREDIENT]-(r:Recipe)-[:HAS_INGREDIENT]->(rice:Product{ name:"rice" })
WITH r, bad_food, bad_recipe
WHERE NOT (r IN bad_recipe)
MATCH (r)-[:HAS_INGREDIENT]->(p:Product)
WITH r.name as recipe, p
return recipe, collect(p.name) as ingredients

My friends are coming, what can I (Michael) cook for a dessert to please them all?

//cheching products Michael and his friends should not eat
MATCH (my_bad_food:Product)<-[:IS_ALLERGIC_TO|HATES]-(m:Person { name:"Michael" })-[IS_FRIEND_TO]-(f:Person)-[:IS_ALLERGIC_TO|HATES]->(bad_food:Product)
WITH m, bad_food, my_bad_food

//checking the recipes for desserts that they should not eat
MATCH (r:Recipe { type:"dessert" })-[:HAS_INGREDIENT]->(p:Product)
WITH m, bad_food, my_bad_food, p, r
WHERE p IN bad_food OR p IN my_bad_food
WITH m, r AS bad_recipe

//checking the recipes for dessert that they can eat
MATCH (r:Recipe { type:"dessert" })-[:HAS_INGREDIENT]->(p:Product)
WITH m,  bad_recipe, r
WHERE NOT (r IN bad_recipe)
WITH r AS rec_dessert, m

//checking the favourite ingredients that the allowed recipe can contain
MATCH (m)-[:LOVES]->(favorite:Product)<-[:HAS_INGREDIENT]-(rec_dessert)
RETURN DISTINCT rec_dessert.name as recommended_dessert

How to enhance the model

The presented graph model can be extensible according to the data sources and the needed applications.

de160e9f

The following relations can be added as it is presented on the picture:

  • the relation LIKES between Person and Recipe can be added to add the functionality of recipes evaluation. Then, the recommendation of recipes can be done based on the personal preferences but also on my friends recommendations.

  • the relation CONTAINS between particular Products (e.g. wheat CONTAINS gluten) can be added to improve the accuracy of the recommendation

  • HAS_SUBCATEGORY between particular Products (e.g. chocolate HAS_SUBCATEGORY white chocolate) can be added to improve the accuracy of the recommendation

Summary

Presented model is very simple - just a few nodes' and relations' types but it seems it has potential to answer important people' needs. With possible enhancement that has been shown above, the recommendation algirithms can be more accurate and better ajusted to people requirements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment