使用 Neo4j 节点扩展 Ruby on Rails ActiveRecord。保持 RDBMS 并利用 Neo4j 查询的强大功能。
This gem is not stable. There are currently no stable versions. We're working on fixing this right now. Apologies.
Make your ActiveRecords stored and searchable on Neo4j graph database, in order to make fast graph queries that MySQL would crawl while doing them. Originally by @elado.
Neoid is to Neo4j as Sunspot is to Solr. You get the benefits of Neo4j's speed while keeping your schema on your RDBMS.
Neoid does not require JRuby. It's based on the Neography gem which uses Neo4j's REST API.
Neoid offers querying Neo4j for IDs of objects and then fetch them from your RDBMS, or storing all desired data on Neo4j.
Important: If you are hosting your application on Heroku with Neoid, GrapheneDB does support Gremlin code; their add-on is located here. Also be reminded that the Gremlin code is actively being refactored into Cypher.
See Changelog. Including some breaking changes (and solutions) from previos versions.
Add to your Gemfile and run the bundle command to install it.
gem 'neoid'Requires Ruby 1.9.3 or later and Neo4j 1.9.8.
We're currently working to bump to 2.1.x land, but for now, you have to use 1.9.8. To get started, install neo4j locally in your project with:
gem install neo4j-core --pre
rake neo4j:install[community,1.9.8]
rake neo4j:startInitializer neography and neoid in an initializer that is prefixed with 01_, such as config/initializers/01_neo4j.rb:
ENV["NEO4J_URL"] ||= "http://localhost:7474"
uri = URI.parse(ENV["NEO4J_URL"])
$neo = Neography::Rest.new(uri.to_s)
Neography.configure do |c|
c.server = uri.host
c.port = uri.port
if uri.user && uri.password
c.authentication = 'basic'
c.username = uri.user
c.password = uri.password
end
end
Neoid.db = $neo
Neoid.configure do |c|
# should Neoid create sub-reference from the ref node (id#0) to every node-model? default: true
c.enable_subrefs = true
endFor nodes, first include the Neoid::Node module in your model:
class User #
user.neo_node.display_name # => "elado"
rel = user.likes.first.neo_relationship
rel.start_node # user.neo_node
rel.end_node # user.movies.first.neo_node
rel.rel_type # 'likes'If you'd like to save nodes manually rather than after_save, use auto_index: false:
class User returns a Neography hash
Neoid::Node.from_hash(Neoid.db.get_node_auto_index(Neoid::UNIQUE_ID_KEY, user.neo_unique_id))
# => returns a Neography::NodeIf Subreferences are enabled, you can get the subref node and then get all attached nodes:
Neoid.ref_node.outgoing('users_subref').first.outgoing('users').to_a
# => this, according to Neography, returns an array of Neography::Node so no conversion is neededThese examples query Neo4j using Gremlin for IDs of objects, and then fetches them from ActiveRecord with an in query.
Of course, you can store using the neoidable do |c| c.field ... end all the data you need in Neo4j and avoid querying ActiveRecord.
Most liked movies
gremlin_query = "Elad"
Neoid.batch(batch_size: 100) do
User.all.each(&:neo_save)
end.then do |results|
# results is an array of the script results from neo4j REST.
results[0].name # => "Elad"
endNodes and relationships in the results are automatically converted to Neography::Node and Neography::Relationship, respectively.
With individual then as well as then for the entire batch:
Neoid.batch(batch_size: 30) do |batch|
(1..90).each do |i|
(batch << [:create_node, { name: "Hello #{i}" }]).then { |result| puts result.name }
end
end.then do |results|
puts results.collect(&:name)
endWhen in a batch, neo_save adds gremlin scripts to a batch, instead of running them immediately. The batch flushes whenever the batch_size option is met.
So even if you have 20000 users, Neoid will insert/update in smaller batches. Default batch_size is 200.
If you have an existing database and just want to integrate Neoid, configure the neoidables and run in a rake task or console.
Use batches! It's free, and much faster. Also, you should use includes to incude the relationship edges on relationship entities, so it doesn't query the DB on each relationship.
Neoid.batch do
[ Like.includes(:user).includes(:movie), OtherRelationshipModel.includes(:from_model).includes(:to_model) ].each { |model| model.all.each(&:neo_save) }
NodeModel.all.each(&:neo_save)
endThis will loop through all of your relationship records and generate the two edge nodes along with a relationship (eager loading for better performance). The second line is for nodes without relationships.
For large data sets use pagination. Better interface for that in the future.
Whenever the neo_node on nodes or neo_relationship on relationships is called, Neoid checks if there's a corresponding node/relationship in Neo4j (with the auto indexes). If not, it does the following:
id attribute and all other attributes from neoidable's field listThen, when it needs to find it again, it just seeks the auto index with that ActiveRecord id.
Like Nodes, it uses an auto index, to look up a relationship by ActiveRecord id
neoidable, it fetches the start_node and end_nodeneo_node on both, in order to create the Neo4j nodes if they're not created yet, and creates the relationship with the type from the options.In order to test your app or this gem, you need a running Neo4j database, dedicated to tests.
I use port 7574 for testing.
To run another database locally (read here too):
Copy the entire Neo4j database folder to a different location,
or
symlink bin, lib, plugins, system, copy conf to a single folder, and create an empty data folder.
Then, edit conf/neo4j-server.properties and set the port (org.neo4j.server.webserver.port) from 7474 to 7574 and run the server with bin/neo4j start
In environments/test.rb, add:
ENV["NEO4J_URL"] = 'http://localhost:7574'In your spec_helper.rb, add the following configurations:
config.before :all do
Neoid.clean_db(:yes_i_am_sure)
end
config.before :each do
Neoid.reset_cached_variables
endRun the Neo4j DB on port 7474, and run rake from the gem folder.
Please create a new issue if you run into any bugs. Contribute patches via pull requests. Write tests and make sure all tests pass.
Developed by @elado and @BenMorganIO
暂无开放 Issues,或尚未同步最近议题。