The elasticsearch-rails2
library is based on the
elasticsearch-model
and builds on top of the
the elasticsearch
library.
It aims to simplify integration of Ruby on Rails 2.3 models (ActiveRecord
)
with the Elasticsearch search.
(If your app is in Ruby on Rails 2.3 you can't use elasticsearch-model
because it requires Ruby on Rails >= 3.0)
The library is compatible with Ruby 1.9.3.
Installation
Add this line to your application's Gemfile:
gem 'elasticsearch-rails2'
And then execute:
$ bundle
Or install it yourself as:
$ gem install elasticsearch-rails2
Usage
Let's suppose you have an Article
model:
require 'elasticsearch/rails2'
class Article < ActiveRecord::Base
include Elasticsearch::Rails2
end
This will extend the model with functionality related to Elasticsearch:
Elasticsearch client
The module will set up a client,
connected to localhost:9200
, by default. You can access and use it as any other Elasticsearch::Client
:
Article.client.cluster.health
# => { "cluster_name"=>"elasticsearch", "status"=>"yellow", ... }
To use a client with different configuration, just set up a client for the model:
Article.client = Elasticsearch::Client.new host: 'api.server.org'
Or configure the client for all models:
Elasticsearch::Rails2.client = Elasticsearch::Client.new log: true
You might want to do this during you application bootstrap process, e.g. in a Rails initializer.
Please refer to the
elasticsearch-transport
library documentation for all the configuration options, and to the
elasticsearch-api
library documentation
for information about the Ruby client API.
Searching
For starters, we can try the "simple" type of search:
response = Article.search 'fox dogs'
response.took
# => 3
response.results.total
# => 2
response.results.first._score
# => 0.02250402
response.results.first._source.title
# => "Quick brown fox"
Search results
The returned response
object is a rich wrapper around the JSON returned from Elasticsearch,
providing access to response metadata and the actual results ("hits").
Each "hit" is wrapped in the Result
class, and provides method access
to its properties via Hashie::Mash
.
The results
object supports the Enumerable
interface:
response.results.map { |r| r._source.title }
# => ["Quick brown fox", "Fast black dogs"]
response.results.select { |r| r.title =~ /^Q/ }
# => [#<Elasticsearch::Model::Response::Result:0x007 ... "_source"=>{"title"=>"Quick brown fox"}}>]
In fact, the response
object will delegate Enumerable
methods to results
:
response.any? { |r| r.title =~ /fox|dog/ }
# => true
To use Array
's methods (including any ActiveSupport extensions), just call to_a
on the object:
response.to_a.last.title
# "Fast black dogs"
Search results as database records
Instead of returning documents from Elasticsearch, the records
method will return a collection
of model instances, fetched from the primary database, ordered by score:
response.records.to_a
# Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (1, 2)
# => [#<Article id: 1, title: "Quick brown fox">, #<Article id: 2, title: "Fast black dogs">]
The returned object is the genuine collection of model instances returned by your database,
The records
method returns the real instances of your model, which is useful when you want to access your
model methods -- at the expense of slowing down your application, of course.
In most cases, working with results
coming from Elasticsearch is sufficient, and much faster. See the
elasticsearch-rails
library for more information about compatibility with the Ruby on Rails framework.
The Elasticsearch DSL
In most situation, you'll want to pass the search definition in the Elasticsearch domain-specific language to the client:
response = Article.search query: { match: { title: "Fox Dogs" } },
highlight: { fields: { title: {} } }
response.results.first.highlight.title
# ["Quick brown <em>fox</em>"]
You can pass any object which implements a to_hash
method, or you can use your favourite JSON builder
to build the search definition as a JSON string:
require 'jbuilder'
query = Jbuilder.encode do |json|
json.query do
json.match do
json.title do
json.query "fox dogs"
end
end
end
end
response = Article.search query
response.results.first.title
# => "Quick brown fox"
Index Configuration
By default, index name and document type will be inferred from your class name, you can set it explicitely, however:
class Article
index_name "articles-#{Rails.env}"
document_type "post"
end
For index_name
there is a global setting in case you want to use the same index for all models:
Elasticsearch::Rails2.index_name = 'production'
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request