Overview Why Neo4j? Introduction to Neo4j Cypher Neo4j in Ruby Setup The Fun Stuff Eager Loading Recommendations Doing More An example Sinatra application The asset_portal application Getting Help More Screencasts Integrations with other gems Goals This course provides an overview… Learn More →
This course provides an overview on everything that you need to build a Neo4j application with the Ruby programming language. Ruby on Rails and Sinatra examples are given but any web framework (or lack thereof) can be used.
You should have Ruby installed on your system. Some experience with Ruby and/or Rails is suggested.
Let’s say you would like to write a web application to track entities for yourself or your organization. Being a good DRY programmer you might decide that what you want is an asset portal: an application which gives you an GUI for browsing and editing entities while also making it easy to define new assets. This guide will show you how you might start creating such an application using Ruby on Rails and Neo4j.
Neo4j is the world’s most popular graph database. This offers a number of advantages:
- Neo4j provides a schemaless representation of both entities and relationships between entities.
- Relationships between entities are traversed rather than joined. Traversals explore the local subgraph meaning that query times stay the same as your database grows.
- Because of the traversal paradigm we think in terms of the complex relationships in our data without worrying as much how to model it
Rubyists generally prefer tools which are developer friendly and which don’t bother you with details until it’s neccessary. Neo4j makes it easy to create nodes and relationships in whatever way seems most natural, but you can also change the structure of your database with a query.
Introduction to Neo4j
Connected information is everywhere in our world. Neo4j was built to efficiently store, handle, and query highly connected elements in your data model. With a powerful and flexible data model you can represent your real-world, variably structured information without a loss of fidelity. The property graph model is easy to understand and handle, especially for object oriented and relational developers.
The property graph model consists of:
Nodes which have:
- properties: schemaless key/value pairs
- labels: describe and group nodes much like tables group rows, but nodes can have multiple labels
Relationships which connect two nodes directionally have:
- properties: schemaless key/value pairs
- A type: gives a description of how it connects the two nodes
While relationships are directional, querying relationships in either direction has no associated performance cost.
Cypher is Neo4j’s built-in query language. Cypher queries look like:
MATCH clause is the most common starting point for Cypher queries. It defines a pattern for which to search and returns one result per match. For example, we might get the following two matches:
RETURN clause we would end up returning a table such as:
Here you see we can return entire entities in our database rather than just properties. This might be returned as a
Hash in Ruby, though by default in the Neo4j.rb gems these are wrapped in an object.
This is very handy, but it would also be nice to avoid the duplication of our
Person node. You can perform the same match but instead use the
collect function to aggregate the values:
While it’s possible to get started using the Neo4j.rb without learning Cypher, it is a very powerful way to query a Neo4j database and is worth learning. Also since the Neo4j.rb project works by making Cypher queries to Neo4j it is good to understand Cypher as your queries get more complex. There is a Cypher tutorial if you would like to learn more.
Neo4j in Ruby
For this guide we will be using the Neo4j.rb project. The project consists of the following gems:
- neo4j A Object-Graph-Mapper (OGM) for the Neo4j graph database. It tries to follow API conventions established by ActiveRecord but with a Neo4j flavor.
- neo4j-core A low level driver for connecting to Neo4j. Used by the neo4j gem.
- neo4j-rake_tasks A set of rake tasks for installing and managing a Neo4j database within your project. Used by the neo4j-core gem.
Specifically in this guide we will be using the
ActiveRel modules from the
neo4j gem to model nodes and relationships from our database.
The following example is in Ruby on Rails, but there is a Sinatra example below.
Here we describe how to create a fresh Rails application with Neo4j as the database. If you have an existing Rails application you can refer to the Neo4j.rb documentation.
Here is how you would setup your asset portal Rails app:
What do these commands do?
The first creates a new Rails app skipping
-O flag) and setting up Neo4j.rb in your project (the
-m flag). Then we change into our directory and install the latest version of the community edition of Neo4j into our app directory (into
db/neo4j/development/). Last we start up our copy of Neo4j.
Next you should open up your
config/application.rb file and find the
config.neo4j.* lines. Here you have a choice between *embedded* and server modes:
- Server mode allows you to connect to Neo4j via it’s HTTP JSON APIs.
- Embedded mode requires JRuby and allows you to run Neo4j as part of your JRuby process. This gives you access to the Neo4j Java APIs directly.
By default you will be configured to Neo4j in server mode on the default port (7474). If you would like something other than the default console the documentation.
| By default the |
To see an example of setting up Neo4j in Rails check out this short screencast.
In this guide we’ll be setting up different
ActiveNode models which will serve as assets. This is a textbook example of where we can use class inheritance in Neo4j.rb. First we create some basic models:
This will generate scaffolds just like any Rails application with the exception that the models will be
ActiveNode models rather than
ActiveRecord models and will look like this:
Since Neo4j is schemaless we need to define our properties in our model.
| By default there will be a |
To learn more about properties check out this short screencast.
Once we’ve set up those models we can define our asset models like so:
That should generate a model which looks like this:
You should change that to look like the following (note the
Asset superclass definition):
| You can remove the |
| We need to specify our Neo4j relationship directions and types here. Additionally since |
By inheriting from
Book model will create nodes with two labels (
Asset). Likewise when you query for nodes via the
Book model it will only find nodes which have both labels.
Lastly we just need to make a couple of small fixes. Change these lines to get the names of book authors and categories:
And change these lines to be able to choose the author when creating or editing books:
And so that you can set your associations, change the
book_params method in the
BooksController to remove the
Now that we’ve created our scaffolding let’s run the migrations to create constraints for our models and then start up our Rails server:
From there you can create, update, browse, and delete books via the scaffolding. You can visit
/categories to get entry points into the various sections.
The Fun Stuff
If you just wanted to do simple CRUD operations there are plenty of other databases to choose from. How can we do something a bit more fun using the power of Neo4j?
First let’s look at a performance improvement which isn’t available from
ActiveRecord. When you go to your list of books you should see something like this in your log:
If you find that a bit hard to read then you can add the following line to your application’s configuration:
Don’t forget to restart your Rails server!
Once you done this your log will look more like this:
First the books are loaded and then separate queries are made to get all of the authors and categories for those books.
ActiveRecord you would need to specify an
includes in order to make this happen rather than having each entity loaded individually.
ActiveNode, on the other hand, makes the assumption that if you refer to an association from a list of items, you’re almost certainly going to want that association for all of the objects.
But we can do better! Now modify the
index action of the
BooksController like so:
with_associations method is similar to
includes, except that our associations are loaded in the same query using the
collect() function demonstrated earlier.
What we get is a list of
Book objects which are pre-populated with authors and categories.
You may have heard that Neo4j makes building recommendations from your data easy. Let’s take a look at how we might make some recommendations. For this we’re going to introduce
has_many associations. Since entities are connected via relationships in Neo4j the database doesn’t draw any distinction for when we want to have a single relationship or many to/from a node. In our Ruby apps, however, it is often convenient to be able to draw this distinction.
To learn more about associations check out this short screencast.
First change the
category association for the
Don’t forget to change the
:category argument in the
with_associations call in the controller to
Then add a
books association to the
Since we’ve changed the
has_many for the book categories we should update our scaffold UI to match:
Now with the ability for a book to have many categories and for a category to have many books you can have a much better picture about recommending books.
It is simple to get a start on querying potential recommendations. Try running this in your Rails console:
It should show you the query which was made and it should look something like:
This query is finding all of the books that share categories with all other books. This isn’t particularly useful until we start introducing some variables. In the
neo4j gem this is called association chaining. For more information about association chaining check out this short screencast:
What if you wanted to list every book and find out, for every other book with which it shares a category, how many categories it shares?
Notice how we’re starting to assign variables. These eventually become the variables in the cypher query made to Neo4j.
Taking it a step further, let’s create a query which finds, for all books, the books which share at least two categories. We can also display these recommendations in our app like so:
Of course we don’t want to put too much logic in the controller, so let’s extract this to a model class method:
all method starts it off we can actually add this to an existing chain rather than just calling it on the
Book model. For example, if we had a
recent scope which only gave us books from the past ten years:
Are you getting into the idea of using Neo4j? Great! There are a number of resources to help you along with your journey.
An example Sinatra application
For the example view see the one from the result of the Rails example above.
The asset_portal application
You can find the result of this guide in it’s GitHub repository. If you would like to play with a more developed application check out our asset_portal app. The project introduces a single
AssetController to avoid the duplication from this guide and also uses other tools like Semantic UI for a cleaner interface.
The maintainers of the
Neo4j.rb project love to help! You can ask a question on StackOverflow (make sure to use the
neo4j.rb tag), or join us in our Gitter chat room. You can also check out the website and the documentation.
There is also a wonderful public Slack group for the wider Neo4j community if you have questions about installation, configuration, Cypher, etc…
In addition to the screencasts embedded in this guide there are two others to help you learn more about the
Integrations with other gems
There are many common gems that you’ll want to use with your Neo4j database. Many are supported for the Neo4j.rb project:
Admin User Interface
Integration With the Neo4j Spatial Plugin
Ruby Object Manager