Skip to content

Commit

Permalink
+ rake task for creating nodes and its relationships in Neo4j
Browse files Browse the repository at this point in the history
  • Loading branch information
Stanley committed Jul 25, 2011
1 parent b8c16b6 commit eb37770
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 64 deletions.
4 changes: 3 additions & 1 deletion Gemfile
Expand Up @@ -3,7 +3,9 @@ source :rubygems
group :app do
gem 'thin'
gem 'sinatra'
gem 'yajl-ruby'
gem 'neo4j', '1.1.2', :platforms => :jruby
gem 'unicode'
gem 'jruby-openssl'
end

group :test do
Expand Down
66 changes: 57 additions & 9 deletions Gemfile.lock
@@ -1,27 +1,69 @@
GEM
remote: http://rubygems.org/
specs:
builder (3.0.0)
cucumber (1.0.0)
abstract (1.0.0)
actionpack (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.5.0)
rack (~> 1.2.1)
rack-mount (~> 0.6.14)
rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
activemodel (3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
i18n (~> 0.5.0)
activesupport (3.0.9)
bouncy-castle-java (1.5.0146.1)
builder (2.1.2)
cucumber (1.0.2)
builder (>= 2.1.2)
diff-lcs (>= 1.1.2)
gherkin (~> 2.4.1)
gherkin (~> 2.4.5)
json (>= 1.4.6)
term-ansicolor (>= 1.0.5)
daemons (1.1.4)
diff-lcs (1.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
eventmachine (0.12.10)
eventmachine (0.12.10-java)
fuubar (0.0.5)
rspec (~> 2.0)
rspec-instafail (~> 0.1.4)
ruby-progressbar (~> 0.0.10)
gherkin (2.4.1)
gherkin (2.4.5)
json (>= 1.4.6)
gherkin (2.4.5-java)
json (>= 1.4.6)
i18n (0.5.0)
jruby-openssl (0.7.4)
bouncy-castle-java
json (1.5.3)
json (1.5.3-java)
mime-types (1.16)
rack (1.3.0)
rack-test (0.6.0)
neo4j (1.1.2-java)
activemodel (>= 3.0.0)
orm_adapter (>= 0.0.3)
railties (>= 3.0.0)
will_paginate (~> 3.0.pre)
orm_adapter (0.0.5)
rack (1.2.3)
rack-mount (0.6.14)
rack (>= 1.0.0)
rack-test (0.5.7)
rack (>= 1.0)
railties (3.0.9)
actionpack (= 3.0.9)
activesupport (= 3.0.9)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (~> 0.14.4)
rake (0.9.2)
rdoc (3.8)
rest-client (1.6.3)
mime-types (>= 1.16)
rspec (2.6.0)
Expand All @@ -36,24 +78,30 @@ GEM
ruby-progressbar (0.0.10)
sinatra (1.2.6)
rack (~> 1.1)
tilt (< 2.0, >= 1.2.2)
tilt (>= 1.2.2, < 2.0)
term-ansicolor (1.0.5)
thin (1.2.11)
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.14.6)
tilt (1.3.2)
yajl-ruby (0.8.2)
tzinfo (0.3.29)
unicode (0.4.0)
will_paginate (3.0.pre2)

PLATFORMS
java
ruby

DEPENDENCIES
cucumber
fuubar
jruby-openssl
neo4j (= 1.1.2)
rack-test
rest-client
rspec
sinatra
thin
yajl-ruby
unicode
71 changes: 61 additions & 10 deletions Rakefile
@@ -1,5 +1,9 @@
#!/usr/bin/env jruby
# encoding: utf-8

require 'rake'
require 'restclient'
require 'unicode'
#require 'spec/rake/spectask'
require File.join(File.dirname(__FILE__), 'config', 'environment')

Expand All @@ -18,7 +22,60 @@ require File.join(File.dirname(__FILE__), 'config', 'environment')

namespace :neo4j do
desc "Populate graph"
task :import do
task :import, [:db] do |t, args|

require 'neo4j'
db = CONFIG['couch'] +'/'+ args[:db]
stops = {}

Neo4j::Transaction.run do
# Get all stops
JSON.parse(RestClient.get db+'/_design/Stops/_view/by_name?group_level=1')['rows'].
each do |row|
location = row['value']['location']
name = Unicode::upcase(row['key'].first)
stops[name] = Neo4j::Node.new(location)
end

# Destination hub name
destination = nil
# Node from which we're adding connection
from = nil

# Get all timetables
JSON.parse(RestClient.get db+'/_design/Timetables/_view/by_source?limit=200&descending=true')['rows'].
map{|row| row['value']}.
each do |timetable|
# timetable's destination
dest = Unicode::upcase((timetable['destination'] || timetable['route'].split('-').last).strip)
timetable['stop'] = Unicode.upcase(timetable['stop'])

to = destination === dest ? from : stops[dest]
from = stops[timetable['stop']] # timetables['stop_id']

puts "#{timetable['line']}\n" if destination != dest
destination = dest

if to == from
plus_one = timetable['stop'] +"+1"
unless from = stops[plus_one]
# create new node
from = stops[plus_one] = Neo4j::Node.new({}) # todo location
end
end

puts "<- #{timetable['stop']} (#{from})"
puts "ERROR: #{dest}" unless to

# Get or create relationship between from and to stops
unless connection = from.rels(:connections).outgoing.to_other(to).first
connection = Neo4j::Relationship.new(:connections, from, to)
connection['cost'] = 0
end
# add departures from current timetable
connection['departures'] = "?"
end
end
end
end

Expand All @@ -28,16 +85,10 @@ namespace :couchdb do
task :views, [:db] do |t, args|
couch = CONFIG['couch'] +'/'+ args[:db]
designs = File.read './views/designs.json'
RestClient.post couch +'/_bulk_docs', designs, :content_type => :json, :accept => :json do |resp|
RestClient.post couch +'/_bulk_docs', designs, :content_type => :json, :accept => :json do |resp, req|
JSON.parse(resp).each do |status|
if(status['error'] == 'conflict')
old = JSON.parse(RestClient.get(couch +'/'+ status['id']).gsub(/\n/,''))
# Replace new lines with \n within strings then parse as JSON
new = JSON.parse(designs.gsub(/(\"[^\"]+\")/){|str| str.gsub(/\n/, '\n') })['docs'].
find{ |doc| doc['_id'] == status['id'] } # find conflicted document
RestClient.post couch, old.merge(new).to_json, :content_type => :json, :accept => :json do |resp|
p resp
end
if(status['error'] === 'conflict')
p status
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/main.rb
Expand Up @@ -15,7 +15,7 @@ class Bagatela < Sinatra::Base

# Welcome message
get '/' do
{message: 'Welcome aboard!', version: VERSION}.to_json
{:message => 'Welcome aboard!', :version => VERSION}.to_json
end

# Search for connections
Expand Down
39 changes: 19 additions & 20 deletions app/models/connection.rb
Expand Up @@ -3,30 +3,29 @@
class Connection
include Neo4j::RelationshipMixin

property :cost # length in meters
property :timetables # every departure in direction
property :line # used to determine if a passenger have to make a transfer
property :cost # distance in meters
property :departures # hash of departures where key is a time and value is pair: line and arrival time

# Returns nil if there are no more runs
# Otherwise return cost (that is waiting time + trip time), departure time and trip time
def by_time(time)
dep, dur = next_run(time) || next
[dep-time+dur, dep, dur]
end
#def by_time(time)
#dep, dur = next_run(time) || next
#[dep-time+dur, dep, dur]
#end

# Returns nil if there are no more runs
def by_dist(time)
dep, dur = next_run(time) || next
[cost || start_node.by_dist(end_node), dep, dur]
end
## Returns nil if there are no more runs
#def by_dist(time)
#dep, dur = next_run(time) || next
#[cost || start_node.by_dist(end_node), dep, dur]
#end

private
#private

# Finds next run and returns its departure time and waiting time
def next_run(time)
# TODO: do not use json!
JSON.parse(timetables).sort.
map{|dep, _| [dep.to_i, _]}.
find{|dep, _| dep.to_i >= time}
end
## Finds next run and returns its departure time and waiting time
#def next_run(time)
## TODO: do not use json!
#JSON.parse(timetables).sort.
#map{|dep, _| [dep.to_i, _]}.
#find{|dep, _| dep.to_i >= time}
#end
end
40 changes: 20 additions & 20 deletions app/models/hub.rb
Expand Up @@ -3,32 +3,32 @@
class Hub
include Neo4j::NodeMixin

property :name, :lat, :lng
property :name, :lat, :lon

has_n(:connections).to(Hub).relationship(Connection)

R = 6371 * 1000 # Earth radius in meters
RAD = Math::PI / 180 # Converts degrees do radians
#R = 6371 * 1000 # Earth radius in meters
#RAD = Math::PI / 180 # Converts degrees do radians

def to_s
"Hub #{self.name}"
end
#def to_s
#"Hub #{self.name}"
#end

# Resturns distance in meters to given hub
def by_dist(hub)
a, b = [self.lat, self.lng], [hub.lat, hub.lng]
dLat = (b[0] - a[0]) * RAD
dLng = (b[1] - a[1]) * RAD
## Resturns distance in meters to given hub
#def by_dist(hub)
#a, b = [self.lat, self.lng], [hub.lat, hub.lng]
#dLat = (b[0] - a[0]) * RAD
#dLng = (b[1] - a[1]) * RAD

d = Math.sin(dLat / 2) ** 2 +
Math.cos(a[0] * RAD) * Math.cos(b[0] * RAD) *
Math.sin(dLng / 2) ** 2
#d = Math.sin(dLat / 2) ** 2 +
#Math.cos(a[0] * RAD) * Math.cos(b[0] * RAD) *
#Math.sin(dLng / 2) ** 2

R * 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1-d))
end
#R * 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1-d))
#end

def by_time(hub)
# estimated time to hub in minutes given average speed of 20km/h
by_dist(hub)/1000/20 *60
end
#def by_time(hub)
## estimated time to hub in minutes given average speed of 20km/h
#by_dist(hub)/1000/20 *60
#end
end
10 changes: 10 additions & 0 deletions app/models/stop.rb
@@ -0,0 +1,10 @@
class Stop
include Neo4j::NodeMixin

property :id, :lat, :lon
index :id

has_n(:connections).to(Stop).relationship(Connection)
has_n(:transfers).to(Stop).relationship(Transfer)

end
4 changes: 4 additions & 0 deletions app/models/transfer.rb
@@ -0,0 +1,4 @@
class Transfer
include Neo4j::RelationshipMixin
property :cost # distance in meters
end
8 changes: 5 additions & 3 deletions config/environment.rb
@@ -1,11 +1,13 @@
require 'rubygems'
#require 'neo4j'
require 'neo4j'
require 'yaml'
require 'json'
require File.join(File.dirname(__FILE__), 'exceptions')

#$: << File.join(File.dirname(__FILE__), '..', 'app', 'models')
#require 'connection'
$: << File.join(File.dirname(__FILE__), '..', 'app', 'models')
require 'connection'
require 'transfer'
require 'stop'
#require 'hub'
#require 'a_star'

Expand Down

0 comments on commit eb37770

Please sign in to comment.