Usage Overview

Flex can integrate your code with elasticsearch in 6 different ways that can be handy in different contexts. From a fully automatic integration, to a very low-level manual interaction:

1. ActiveRecord and Mongoid Integration

When the data you need to index is in your DB, just add the following lines to your ActiveRecord and Mongoid model to sync them:

class MyModel < ActiveRecord::Base
  include Flex::ModelIndexer
  flex.sync self
end

You can add a few other declarations to your models in order to setup parent and child relationship (eventually also polymorphic), and mapping any DB structure to any index structure you might want to design.

(see ActiveRecord And Mongoid Integration)

2. ActiveModel Integration

Manage the elasticsearch index as it were a DB, through ActiveModel models. Get validations and callbacks, typecasting, attribute defaults, persistent storage, with optimistic lock update, finders, chainable scopes etc.

This is very useful when the data don’t come from a DB or when you want to use the elasticsearch index as a data storage, or simply when you want a familiar way to populate and search your index. For example:

class Product
  include Flex::ActiveModel

  attribute :name
  attribute :color, :analyzed => false
  attribute :price, :properties => {'type' => 'float'}, :default => 0
  attribute_timestamps

  validate :name, :presence => true

  scope :red, term(:color => 'red')

end

# indexes the data in elasticsearch
Product.create :name  => 'my_name',
               :color => 'blue',
               :price => 9.99

red_products = Product.red.all
product = Product.find('a09rf')
total   = Product.count

(see ActiveModel Integration)

3. Chainable Scopes and Finders

Almost no elasticsearch knowledge required: a ruby-rails way that covers most searching needs!

Scopes are a great way to define the criteria to search the index in pure ruby. You can mix and match many scopes to create a new search criteria, and finally get your result by calling the usual find, count, delete, first, last, all. You can also use scan_all when you want to process a lot of documents in batches.

class MyClass
  include Flex::Scopes

  scope :red, terms(:color => 'red')

  scope :size do |size|
    terms(:size => size)
  end

  scope :cheaper_than do |p|
    range :price => {:to => p}
  end

end

my_scope      = MyClass.red.size('big')
all_big_red   = my_scope.all
big_red_cheap = my_scope.cheaper_than(10).all

in_range_scope = MyClass.range :price =>{:from => 10, :to => 99.99}
first_in_range = in_range_scope.first

# uses the elasticsearch 'scan' search_type
MyClass.red.scan_all do |batch|
  batch.each {|d| do_something_with(d)}
end

You can use the flex-scopes with every class that includes any Flex module (see flex-scopes)

4. Template Based Usage

Easily design complex search queries in simple YAML that automatically define methods in your classes.

Flex implements a very simple but powerful templating system that allows you to define very elaborate queries and automatically generate the methods to use (and reuse) them. This method is typically used for search queries, that may grow quite complex, but internally Flex uses it everywhere.

Define the Flex source my_source.yml: it’s just a YAML document containing a few elasticsearch queries and placeholder tags:

my_template:
  query:
    term:
      my_attr: <<the_term>>
  facets:
    my_facet:
      ...

Create a class and load the source in the class:

class MySearch
  include Flex::Templates
  flex.load_search_source 'my_source.yml'
end

Use the automatically generated class methods by just passing a hash of variables/values to interpolate:

result = MySearch.my_template :the_string => params[:the_string]
 # or simply
result = MySearch.my_template params

The results contains the untouched structure returned by elasticsearch, just extended (and easily custom-extendable) with the methods you may need to use:

result.collection.each do |document|
  puts document.id, document.title, ...
end

my_facet = result.facets['my_facet']

(see Templating)

5. elasticsearch API Methods Usage

Flex exposes all the elasticsearch API methods as ready to use class methods. A few examples:

Flex.exist? :index => 'my_index'

Flex.count :index => 'my_index',
           :type  => 'my_type'

Flex.get :id    => id,
         :type  => 'my_type',
         :index => 'my_index'

Flex.multi_get :ids   => ids,
               :type  => 'my_type',
               :index => 'my_index'

Flex.delete_by_query :index  => 'my_index',
                     :params => {:q =>'my_field:value'}

Flex.more_like_this :id    => id,
                    :index => 'my_index',
                    :type  => 'my_type'

Flex.stats :index    => %w[my_index my_other_index],
           :type     => %w[my_type my_other_type]
           :endpoint => 'indexing'

Notice: you don’t actually need to pass any explicit :index or :type if you set them as a defaults (see Variables)

You will probably never need to use the API Methods directly, since Flex does the heavy lifting for you, but they cover all the elasticsearch API, so they will be available when you will need to do anything special (see API Methods).

6. Curl-like Usage

This usage is very explicit and mostly useful for experimentation and debugging: you can use the methods HEAD, GET, PUT, POST, DELETE exactly as you would do with curl (also enforced by the unconventional upcase naming):

# you can use a json string
Flex.GET '/my_index/my_type/_search', '{"query":{"match_all":{}}}'

# a ruby hash
Flex.GET '/my_index/my_type/_search', {:query => {:match_all => {}}}

# or a yaml string
Flex.GET '/my_index/my_type/_search', <<-yaml
query:
  match_all: {}
yaml

You don’t need to pass the base uri: just the path since the base_uri is a configuration setting that defaults to the elasticsearch http:://localhost:9200 (see Configuration).

In all methods above you can also use tags in path and data, and get them interpolated with the default or explicit variables, as you do with a regular Flex template (see Curl-like Methods))

Flex.GET '/<<index>>/<<type>>/_search', <<-yaml, :index => 'my_index', :my_term => 'any'
query:
  term:
    my_field: <<my_term>>
yaml