Open pmackay opened 7 years ago
Unfortunately this repo does not work with new procedures. However I had written a minimal set of methods to monkey-patch neo4jrb_spatial so it could work with neo4j 3.x.
Here's it:
First of all, install neo4j_spatial like this:
gem 'neo4jrb_spatial', github: 'neo4jrb/neo4jrb_spatial', branch: 'neo4j-8.x'
Create a neo4j3_spatial.rb
file in your "app/models/concern"
module Neo4j3Spatial
extend ActiveSupport::Concern
module ClassMethods
def create_index!(type: 'SimplePoint')
return if layer?(spatial_index_name)
_query.call('spatial.addLayer({name}, {type}, "lon:lat")')
.params(name: spatial_index_name, type: type).to_a
end
def layer?(name)
_query.call('spatial.layers() YIELD name, signature')
.with(:name).where(name: name).return(:name).any?
end
private
def _query
Neo4j::ActiveBase.new_query
end
end
included do
scope :within_distance, lambda { |options|
Neo4j::ActiveBase
.new_query
.call('spatial.withinDistance({layer}, {coordinate}, {distance}) YIELD node, distance')
.params(layer: spatial_index_name,
coordinate: { lon: options[:lon], lat: options[:lat] },
distance: options[:distance])
.with(:node).where("(node:#{mapped_label_name})")
.pluck(:node)
}
scope :bbox, lambda { |box|
Neo4j::ActiveBase
.new_query
.call('spatial.bbox({layer}, {x1}, {x2}) YIELD node')
.params(layer: spatial_index_name, x1: { lon: box[0], lat: box[1] }, x2: { lon: box[2], lat: box[3] })
.with(:node).pluck(:node)
}
create_index!
end
delegate :layer?, to: :class
def add_to_spatial_index
return if !lat? || !lon? || !layer?(self.class.spatial_index_name)
Neo4j::ActiveBase
.new_query
.match_nodes(n: neo_id)
.with(:n).call('spatial.addNode({layer}, n) YIELD node')
.params(layer: self.class.spatial_index_name).pluck(:n)
end
end
Here's a sample usage:
class YourModel
include Neo4j::ActiveNode
include Neo4j::ActiveNode::Spatial
spatial_index 'your_index'
include Neo4j3Spatial
end
YourModel.within_distance(...)
ecc...
@ProGM hi, really appreciate your answer. I'm testing this out but getting Neo.ClientError.Schema.IndexNotFound: Index
placesdoes not exist
(places being my index name). What is the right way to setup an index now (or layer, but am assuming the index terminology is still being used here)?
I can't really test right now, but the index creation should be provided when including the module. (check the last line of the "included" block)
You can manually trigger it by using YourModel.create_index!
.
Don't forgot to call node_instance. add_to_spatial_index
after creating a new node.
Let me know if this helps :)
Thanks for the help :) I wasnt calling within_distance
properly as a scope method, re-reviewing it after your comments helped. I think the error response was confusing me a bit. So I've got basic spatial query working!
BTW, I had to get a local copy of the gem and increase the dependency version on neo4j
so it allowed v8, otherwise bundle
wouldnt work. Perhaps that needs tweaking in your branch?
Do you know of any example code of how to chain queries so a spatial and other kinds of queries can be combined? Is it actually possible to chain these scopes? The return value from the within_distance
scope is an array so it cannot accept further scopes.
@pmackay Not sure about it.
To make the query chainable, just remove the pluck(:node)
from the scope chain ;)
scope :within_distance, lambda { |options|
Neo4j::ActiveBase
.new_query
.call('spatial.withinDistance({layer}, {coordinate}, {distance}) YIELD node, distance')
.params(layer: spatial_index_name,
coordinate: { lon: options[:lon], lat: options[:lat] },
distance: options[:distance])
.with(:node).where("(node:#{mapped_label_name})")
}
Example:
Yourmodel. within_distance('...').where(node: { some_property: 'some_value' }).pluck(:node)
I get a following error when I run create_index!
NameError: uninitialized constant Neo4j::ActiveBase
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/aws-s3-0.6.3/lib/aws/s3/extensions.rb:212:in `const_missing_from_s3_library'
from (irb):2
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.1/lib/rails/commands/console.rb:110:in `start'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.1/lib/rails/commands/console.rb:9:in `start'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.1/lib/rails/commands.rb:17:in `<top (required)>'
from /Users/jiyou/Desktop/tilr/tilr-api/bin/rails:9:in `<top (required)>'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from /Users/jiyou/.rbenv/versions/2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from -e:1:in `<main>'
@kroyagis Are you using the neo4j gem 8.0+?
Sorry, I was using 7.2.x at the time I posted this. I upgraded to 8.0.x and it does recognize ActiveBase. I'm currently solving different problems so this can be closed! Thank you.
Please could I clarify, is there a configuration of neo4j, neo4j-spatial, neo4jrb and neo4jrb_spatial that works for Neo4J 3.x? This issue suggests there isnt because indexes were changes for spatial procedures. Would #14 resolve this compatibility problem?
@ProGM would appreciate your input.