Skip to content

Neo4j::Rails Lucene

Andreas Ronge edited this page Apr 26, 2012 · 11 revisions

You can use Lucene to find nodes. A common use case is to find one or more nodes/relationship and then traverse from them (using the Traversal methods or a Cypher Query).

See also Neo4j::Core-Cypher, Neo4j::Wrapper-Rules-and-Functions and Neo4j::Core-Traverse for alternative of finding nodes and relationships.

Declaring Lucene Index

You use the Neo4j::Rails::Model#property and Neo4j::Rails::Relationship#property to declare lucene index (same as for Neo4j::NodeMixin, see Neo4j::Wrapper-Lucene

Example:

class Role < Neo4j::Rails::Relationship
  property :since, :type => Fixnum, :index => :exact
end

Notice for the unique validations and unique entities (e.g. Neo4j::Rails::Model.get_or_create) method to work you must declare an index, see Neo4j::Rails-Persistence.

The find and all methods use the model’s Lucene index to search for either one or a set of nodes respectively. Make sure to index the properties that you’ll query on.

Another example:

class IceCream < Neo4j::Model
  property :flavour, :index => :exact
  property :cone, :index => :exact
end

See Neo4j::Wrapper-Lucene and Neo4j::Core-Lucene for more documentation how to declare and use a lucene index.

Find

The Neo4j::Rails::Model.find and Neo4j::Rails::Relationship.find method behaves different compared to Neo4j::Node.find and Neo4j::NodeMixin.find.
The find method will find the first node that matches its query or nil if one isn’t found.

Example:

IceCream.find('cone: sugar') #=> vanilla_sugar
IceCream.find('flavour: vanilla') #=> who knows?
IceCream.find(:flavour => 'vanilla') #=> same as above
IceCream.find('flavour: chocolate') #=> nil

The find method will also accept a Neo4j node id which is useful for finding a node in a rails controller.

class IceCreamController < ApplicationController
  
  def show
    @ice_cream = IceCream.find(params[:id])
    # . . .
  end

end

The Neo4j::Model also support Active Record like query syntax:

Model.find(:first, :conditions => { :name => "test" }) # works the same as find("name: \"test\"")
Model.find(:first, :conditions => { :id => 10 }) # works the same as find(10) or find("10")

It does also generate finder methods like IceCream.find_by_flavour or find_or_create_by_flavour, see below.

All

The all method will find a set of nodes or relationship. If none is find it will return an empty array.

Some examples:

IceCream.all #=> [vanilla_sugar, vanilla_waffle]
IceCream.all('flavour: vanilla') #=> [vanilla_sugar, vanilla_waffle]
IceCream.all('flavour: vanilla AND cone: sugar') #=> [vanilla_sugar]
IceCream.all('flavour: chocolate') #=> []
IceCream.all(:flavour => 'chocolate')
IceCream.find(:all, :condition => {:flavour => 'chocolate'}, :sort => {:name => :asc})
IceCream.find(:all, 'name: choclate').asc(:name)

Tip: String parameter values with special characters, such as URI’s, should be escaped first before setting or querying to not conflict with the Lucene Query Parser Syntax: + – && || ! ( ) { } ^ " ~ * ? : \ . See Apache Lucene – Query Parser Syntax

escaped = URI.escape( "http://neo4j.rubyforge.org/guides", Regexp.new( "[^#{URI::PATTERN::UNRESERVED}]" ))
Website.find("uri: #{escaped}")

or using String#gsub

escaped = "http://neo4j.rubyforge.org/guides".gsub( /([\+\-\&\|\!\(\)\{\}\[\]\^\"\~\*\?\:\\])/ , "\\\1" )

TIP: The all method also work for subclasses for Neo4j::Rails::Model (but as expected for subclasses of Neo4j::Rails::Relationship).

Fulltext Search

An example of using the lucene full text search index:

class BlogEntry < Neo4j::Rails::Model
  property :text, :index => :fulltext
end

e = BlogEntry.create(:text => 'some long text string')

BlogEntry.find('text: long', :type => :fulltext) #=> e
BlogEntry.all('text: long', :type => :fulltext).size #=> 1

Notice that you need to specify the :fulltext configuration property for both declaring the index and searching.

Dynamic Finders

If you declare an index you neo4j.rb will generate finder methods for you.

Example:

class Person
  property :name
  index :name
end

Person.find_by_name 'andreas'  # with underscore of course, not visible

For a complete list of available methods see Neo4j::Rails::Finders
Clone this wiki locally