Skip to content

Commit

Permalink
Merge 8cbd87a into 39f405c
Browse files Browse the repository at this point in the history
  • Loading branch information
subvertallchris committed Sep 23, 2014
2 parents 39f405c + 8cbd87a commit d8ea584
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 9 deletions.
1 change: 1 addition & 0 deletions config/neo4j/add_classnames.yml
@@ -0,0 +1 @@
# This file is used as the source for adding _classname properties to nodes and relationships.# Within the relationship array, the from/to labels are optional but "type" is not.## nodes:# add: [Lesson, Student, Exam]# overwrite: [Teacher]# relationships:# add:# StudentLesson: { from: 'Student', to: 'Lesson', type: 'enrolled_in' }# overwrite:# ExamLesson: { type: 'has_this_thing' }
Expand Down
115 changes: 106 additions & 9 deletions lib/neo4j/migration.rb
Expand Up @@ -55,15 +55,7 @@ def add_ids_to(model)

new_ids = to_set.times.map { new_id_for(model) }
begin
last_time_taken = Benchmark.realtime do
Neo4j::Session.query("MATCH (n:`#{label}`) WHERE NOT has(n.#{property})
with COLLECT(n) as nodes, {new_ids} as ids
FOREACH(i in range(0,#{to_set - 1})|
FOREACH(node in [nodes[i]]|
SET node.#{property} = ids[i]))
RETURN distinct(true)
LIMIT #{to_set}", new_ids: new_ids)
end
last_time_taken = id_batch_set(label, property, new_ids, to_set)
rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
new_max_per_batch = (max_per_batch * 0.8).round
puts "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
Expand All @@ -72,6 +64,20 @@ def add_ids_to(model)
end
end

def id_batch_set(label, property, new_ids, to_set)
Benchmark.realtime do
Neo4j::Transaction.run do
Neo4j::Session.query("MATCH (n:`#{label}`) WHERE NOT has(n.#{property})
with COLLECT(n) as nodes, #{new_ids} as ids
FOREACH(i in range(0,#{to_set - 1})|
FOREACH(node in [nodes[i]]|
SET node.#{property} = ids[i]))
RETURN distinct(true)
LIMIT #{to_set}")
end
end
end

def default_max_per_batch
900
end
Expand All @@ -84,5 +90,96 @@ def new_id_for(model)
end
end
end

class AddClassnames < Neo4j::Migration
attr_reader :classnames_filename, :classnames_filepath

def initialize
@classnames_filename = 'add_classnames.yml'
@classnames_filepath = File.join(Rails.root.join('db', 'neo4j-migrate'), classnames_filename)
end

def migrate
puts "Adding classnames. This make take some time."
execute(true)
end

def test
puts "TESTING! No queries will be executed."
execute(false)
end

def setup
puts "Creating file #{classnames_filepath}. Please use this as the migration guide."
FileUtils.mkdir_p("db/neo4j-migrate")
unless File.file?(@classnames_filepath)
source = File.join(File.dirname(__FILE__), "..", "..", "config", "neo4j", classnames_filename)
FileUtils.copy_file(source, classnames_filepath)
end
end

private

def execute(migrate = false)
file_init
map = []
map.push :nodes if @model_map[:nodes]
map.push :relationships if @model_map[:relationships]
map.each do |type|
@model_map[type].each do |action, labels|
do_classnames(action, labels, type, migrate)
end
end
end

def do_classnames(action, labels, type, migrate = false)
method = type == :nodes ? :node_cypher : :rel_cypher
labels.each do |label|
puts cypher = self.send(method, label, action)
execute_cypher(cypher) if migrate
end
end

def file_init
@model_map = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(classnames_filepath))
end

def node_cypher(label, action)
where, phrase_start = action_variables(action, 'n')
puts "#{phrase_start} _classname '#{label}' on nodes with matching label:"
"MATCH (n:`#{label}`) #{where} SET n._classname = '#{label}' RETURN COUNT(n) as modified"
end

def rel_cypher(hash, action)
label = hash[0]
value = hash[1]
from = value[:from]
raise "All relationships require a 'type'" unless value[:type]

from_cypher = from ? "(from:`#{from}`)" : "(from)"
to = value[:to]
to_cypher = to ? "(to:`#{to}`)" : "(to)"
type = "[r:`#{value[:type]}`]"
where, phrase_start = action_variables(action, 'r')
puts "#{phrase_start} _classname '#{label}' where type is '#{value[:type]}' using cypher:"
"MATCH #{from_cypher}-#{type}->#{to_cypher} #{where} SET r._classname = '#{label}' return COUNT(r) as modified"
end

def execute_cypher(query_string)
puts "Modified #{Neo4j::Session.query(query_string).first.modified} records"
puts ""
end

def action_variables(action, identifier)
case action
when 'overwrite'
['', 'Overwriting']
when 'add'
["WHERE NOT HAS(#{identifier}._classname)", 'Adding']
else
raise "Invalid action #{action} specified"
end
end
end
end
end

0 comments on commit d8ea584

Please sign in to comment.