ElasticRecord
<img src=“https://secure.travis-ci.org/data-axle/elastic_record.png?rvm=2.0.0” /> <img src=“https://codeclimate.com/github/data-axle/elastic_record.png” />
ElasticRecord is an elasticsearch ORM.
Setup
The usual Gemfile addition:
gem 'elastic_record'
Include ElasticRecord into your model:
class Product < ActiveRecord::Base
include ElasticRecord::Model
end
Searching
ElasticRecord adds the method ‘elastic_search’ to your models. It works similar to active_record scoping:
search = Product.elastic_search
Filtering
If a simple hash is passed into filter, a term or terms query is created:
search.filter(color: 'red') # Creates a 'term' filter
search.filter(color: %w(red blue)) # Creates a 'terms' filter
search.filter(color: nil) # Creates a 'missing' filter
If a hash containing hashes is passed into filter, it is used directly as a filter DSL expression:
search.filter(prefix: { name: "Sca" }) # Creates a prefix filter
An Arelastic object can also be passed in, working similarily to Arel:
# Name starts with 'Sca'
search.filter(Product.arelastic[:name].prefix("Sca"))
# Name does not start with 'Sca'
search.filter(Product.arelastic[:name].prefix("Sca").negated)
# Size is greater than 5
search.filter(Product.arelastic[:size].gt(5))
# Name is 'hola' or name is missing
search.filter(Product.arelastic[:name].eq("hola").or(Product.arelastic[:name].missing))
Helpful Arel builders can be found at github.com/matthuhiggins/arelastic/blob/master/lib/arelastic/builders/filter.rb.
Querying
To create a query string, pass a string to search.query:
search.query("red AND fun*") # Creates {query_string: {"red AND fun*"}}
Complex queries are done using either a hash or an arelastic object:
search.query(match: {description: "amazing"})
Ordering
search.order(:price) # sort by price
search.order(:color, :price) # sort by color, then price
search.order(price: :desc) # sort by price in descending order
Offsets and Limits
To change the ‘size’ and ‘from’ values of a query, use offset and limit:
search.limit(40).offset(80) # Creates a query with {size: 40, from: 80}
Facets
Since term facets are the most common, they are the easiest to add to a query:
search.facet('colors')
It is important to note that adding facets to a query is different than retrieving the results of the query:
search = search.facet('colors').facet('size')
search.facets
#=> {"colors" => ..., "size" => ...}
Getting Results
A search object behaves similar to an active_record scope, implementing a few methods of its own and delegating the rest to Array, and your class.
search.count # Return the number of search results
search.first # Limit results to 1 and return the first result or nil
search.find(id) # Add an ids filter to the existing query
search.as_elastic # Return the json hash that will be sent to elastic search.
The search object behaves like an array when necessary:
search.each do |product|
...
end
Class methods can be executed within scopes:
class Product
def self.increase_prices
all.each do { |product| product.increment(:price, 10) }
end
end
# Increase the price of all red products by $10.
Product.filter(color: 'red').increase_prices
Configuration
While elastic search automatically maps fields, you may wish to override the defaults:
class Product < ActiveRecord::Base
elastic_index.configure do
property :status, type: "string", index: "not_analyzed"
end
end
You can also directly access Product.elastic_index.mapping and Product.elastic_index.settings:
class Product
elastic_index.mapping = {
properties: {
name: {type: "string", index: "analyzed"}
status: {type: "string", index: "not_analyzed"}
}
}
end
Create the index:
rake index:create
Index Administration
Core and Index APIs can be accessed with Product.elastic_index. Some examples include:
Production.elastic_index.create_and_deploy # Create a new index
Production.elastic_index.reset # Delete related indexes and deploy a new one
Production.elastic_index.refresh # Call the refresh API
Production.elastic_index.get_mapping # Get the index mapping defined by elastic search