neo4j: Creating a custom index with neo4j.rb
As I mentioned in my last post I’ve been playing around with the TFL Bus stop location and routes API and 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 each 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 which made it difficult to use in cypher.
Eventually I came across another page which explained that 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 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 when later on in the code I wanted to add a 'route' between stops 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
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.