NoSQL Zone is brought to you in partnership with:

Mark Needham is a software developer and consultant at ThoughtWorks. I have a keen interest in developer testing and object oriented design of systems. Mark is a DZone MVB and is not an employee of DZone and has posted 247 posts at DZone. You can read more from them at their website. View Full User Profile

neo4j: Creating a Custom Index With neo4j.rb

08.15.2012
Email
Views: 995
  • submit to reddit
This article is part of the DZone NoSQL Resource Portal, which is brought to you in collaboration with Neo Technology. Visit the NoSQL Resource Portal for additional tutorials, videos, opinions, and other resources on this topic.

As I mentioned in my last post, I’ve been playing around with the TFL Bus stop location and routes API. One thing I wanted to do was load all the bus stops into a neo4j database using the neo4j.rb gem.

I initially populated the database via neography, but it was taking around 20 minutes per run, and I figured it’d probably be much quicker to populate it directly rather than using the REST API.

Creating nodes is reasonably simple, and the code to add bus stops looks like this:

require 'neo4j'
 
Neo4j::Transaction.run do
  stops_to_add = [ {:name => "Walworth Road", :code => 10001 }]
 
  stops_to_add.each do |stop|
    node = Neo4j::Node.new(:name => stop[:name], :code => stop[:code], :type => "stop")
    puts "Code: #{stop[:code]}, Stop: #{stop[:name]}"
  end
end


I wanted to be able to search for bus stops using cypher, so I needed to create an index for each stop to allow me to do that easily.

I initially tried creating a Stop class and defining the index in there, as suggested in the documentation, but from what I could tell it created an index named after the string representation of the Stop object, making it difficult to use in cypher.

Eventually I came across another page that said I needed to create a ‘custom index’ if I wanted to be able to reference it by name.

I ended up with the following:

class StopsIndex
  extend Neo4j::Core::Index::ClassMethods
  include Neo4j::Core::Index
 
  self.node_indexer do
    index_names :exact => 'stops'
    trigger_on :type => "stop"
  end
 
  index :code
end


As far as I understand, this index gets triggered when you’re inside a transaction while adding a node of type ‘stop’, which is what I’m doing here.

With the index defined this way, it’s now possible to look up stops using cypher:

START stop = node:stops(code = "10001")
RETURN stop


And later, when I wanted to add a ‘route’ between stops in the code, I could look up the stops like so:

Neo4j::Transaction.run do
  stop1 = StopsIndex.find("code: \"10001\"").first
  stop2 = StopsIndex.find("code: \"10002\"").first				
  Neo4j::Relationship.new(:route, stop1, stop2, { :bus_number => 1 })
end

The full code for this is on github.

 

 

 

 

 

Published at DZone with permission of Mark Needham, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Neo Technology is leading the charge for the NoSQL movement.  You can learn more about the Neo4j Graph Database in the project discussion forums and you can try out the new Spring Data Neo4j, which enables POJO-based development.