Basically, you have these ingredients that pair really well together- knowing which ingredients have flavor affinities can produce some amazing new dishes.
The app allows you to add pairings with an ‘affinity’- how well they pair together- and search for an ingredient to find others that pair with it.
The app is built using Grails 2.0 for the front end, visualizations are the result of the very neat d3.js library, and interaction with Neo4j is done using the Neo4j REST Api.
The entire thing is deployed on Heroku (with the Neo4j add-on), while the source is available on github
To get started with Grails 2.0, Neo4j add-on and Heroku, read Aldrins post on the topic: http://thought-bytes.blogspot.in/2012/02/grails-20-heroku-and-neo4j-addon.html
How to deploy Flavorwocky locally as well as on Heroku is documented in the Readme.
The model lends itself very nicely to a graph- as you can see, it is very simple:
Every category is color coded- for convenience, it is stored as a property on the category node, but of course, it doesn’t have to be.
Flavorwocky was also picked as the basis for this challenge because it is a real world use case for a graph, and I wanted this entry to really focus on Neo4j primarily rather than supporting bells and whistles.
When the application starts up, we check if the database is empty. To do this, we perform a traversal from the reference node looking for any categories connected to it. If there are none, then we go ahead and create the set of categories by first creating their nodes, and then a relationship to the reference node. We also create the index “ingredients”, which is used to index ingredient names. Source code: https://github.com/luanne/flavorwocky/blob/master/grails-app/conf/BootStrap.groovy
Adding a pairing involves
- Checking whether either node already exists to avoid recreating it
- Creating both nodes and linking them to their categories in a single transaction
- Creating a relationship between them in the same transaction above
To accomplish this, we used the Batch operation (note, this is still experimental).
Auto complete: This was just an index lookup matching the partially entered ingredient by name. Source: https://github.com/luanne/flavorwocky/blob/master/grails-app/controllers/com/herokuapp/flavorwocky/FlavorwockyController.groovy (autosearch())
We used d3.js to provide two visualizations for the search results. The “Explore” visualization is based on the Node-Link tree; we used a Cypher query to find all ingredients that pair with the searched ingredient up to 3 levels deep, transform it into the appropriate data structure, and render it as JSON. Note, although the visualization interactive, the fetching of data is not. The entire set of data for 3 levels is grabbed at once- a future enhancement would be fetching children only when you expand a node.
Source: https://github.com/luanne/flavorwocky/blob/master/grails-app/controllers/com/herokuapp/flavorwocky/FlavorwockyController.groovy (getSearchVisualizationAsTreeJson())
Although the tree is pretty slick, one shortcoming is that it is a tree- so if children are linked to each other, then you see multiple instances of that ingredient in the tree. Hence we tried another visualization to capture the interconnections between ingredients and also surface interesting facts such as flavor trios- there’s a pretty high chance that if you see a triangle in the network visualization, those three ingredients can be combined together well.
Source: https://github.com/luanne/flavorwocky/blob/master/grails-app/controllers/com/herokuapp/flavorwocky/FlavorwockyController.groovy (getSearchVisualizationAsNetworkJson())
In both examples, the affinity of the pairing is used to calculate the length of the connector between ingredients, indicating shorter connections have ingredients that pair much better than those with longer connections.
That’s about it! There’s so much more that can be done with this application, but it’s going to have to wait for a bit.