Skip to content

donperi/active_elastic

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ActiveElastic

ActiveElastic grants to an ActiveRecord models to query and index documents easily to ElasticSearch.

Requirements

ActiveElastic uses the following gems to work properly:

  • ActiveRecord
  • elasticsearch-model
  • elasticsearch-persitence
  • Sidekiq: For document indexing in the background. (Future version will use ActiveJob)

Installation

Add this line to your application's Gemfile:

gem 'active_elastic', git: 'https://github.com/PixelPerfectTree/active_elastic'

And then execute:

$ bundle install

Getting Started

ActiveElastic is supposed to work with an ActiveRecord model.

Include ActiveElastic::Model to ActiveRecord models to power it up!.

class Post < ActiveRecord::Base
  include ActiveElastic::Model
end

Configuration

ActiveElastic has a few configuration methods that can be used in an initializer.

ActiveElastic::Config.configure do |config|
  config.index_prefix = nil                  # Prefix to be use with indexes name. By default is empty.
  config.prepend_env_in_index = true         # Prepend the current enviroment in document index name.
  config.index_document_after_save = false   # Auto index the document when the model is modified.
  config.use_background_jobs = false         # Use Background Jobs for indexing documents (Sidekiq)
  config.schema_models = [                   # Models to be imported by the schema importer.
    :Posts,
    :Comments
  ]
end

Sidekiq Queues

To use Sidekiq make sure you have this queues in the sidekiq worker: elastic_search_indexer_worker and elatic_model_importer

Query Interface

ActiveElastic adds methods to build queries for ElasticSeach. To begin to build this queries there is a elastic_find method we need to use.

.all

Execute the current query. By default returns all the documents.

Post.elastic_find.all 

.where(field: value)

Filters documents by a condition.

Post.elastic_find.where(active: true)

We also can use a array. This is an alias to .in

Post.elastic_find.where(tags: ['tag1', 'tag2'])

.where_not

Same has where but negated.

.first

Return the first document

.find_by(field: value)

Find a document by a single conditions. Raises ActiveElastic::RecordNotFound if document is not found.

.find(id)

Find a document by ID. Raises ActiveElastic::RecordNotFound if document is not found.

.order(:field)

Add an order condition to the current query.

limit(number)

Add a limit condition to the current query. By default is 10

page(number)

Search document with the offset number useing the current limit.

is_null(:field)

Check if a field is null or missing.

not_null(:field)

Check if a field is not null or missing.

included_in(field: values)

Add a conditions where a field has to have all values

Post.elastic_find.inclued_in(tags: ['tag1', 'tags2']) # Find Post that are tagged with tag1 and tag2

not_inclued_in(field: values)

Same as inclued_in but negated.

filter_using(hash)

Execute all the query methods inside a hash.

conditions = {
  where: { title "Hello World" },
  where: { active: true },
  order: title
}

Post.elaastic_find.filter_using(conditions).all

Scopes

We also can define scopes inside the model.

class Post < ActiveRecord::Base
    include ActiveElastic::Model
    
    elastic_scope :started, -> { where(started: true) }
    default_scope, -> { where(active: true) }
end

Post.elastic_find.started.all

If we have to do a query without the default scope we can use unscoped method to have a query without default scope.

Post.elastic_find.unscoped.started.all

Indexing

Indexing documents

The index_document method calls the indexer worker. By default the worker will index the document without using a backgorund job. If ActiveElastic::Config.use_background_jobs is true, it will use Sidekiq the enqueue the document for indexation in the elastic_search_indexer_worker.

The indexstion use the as_indexed_json method to serialize the object.

Note: Background Jobs are disable in the test enviroment.

Indexing relations

If we want to include relations inside the indexed document. We need to define which relations will be included.

To do this we need to define a index_relations method inside the model and use index_relation method.

class Post < ActiveRecord::Base
  include ActiveElastic::Model
  
  def index_relations(exlucluded_relations=[])
     index_relation(:comments) unless exclude_relations.include? :comments
  end
end

The indexer will call the comments method and serialize its result.

Importing Commands

ActiveElastic provides some Rake tasks to manipulate schemas and import DB data to ElasticSearch. Mosts of this tasks uses the models defined in ActiveElastic::Config.schema_models.

rake active_elastic_schema:create_schema

Create the models schema for ElasticSearch

rake active_elastic_schema:drop_schema

Drop all the ElasticSearch schemas.

rake active_elastic_schema:force_create

Will drop and then create all the model schemas.

rake active_elastic_schema:migrate

Imports all the models's data to ElasticSearch. This job uses Sidekiq's elatic_model_importer queue for background Job.

rake active_elastic_schema:import[ModelName]

Imports the data for a single model to ElasticSearch. This job uses Sidekiq's elatic_model_importer queue for background Job.

rake active_elastic_schema:import_now[ModelName]

Imports the data for a single model to ElasticSearch without using a background job.

Testing with ActiveElastic

Using a record cleaner for ElasticSearch.

You can use this helper module for Rspec to reset ElasticSearch for each test.

# spec/support/elastic_helper.rb
module ElasticHelper
  def elastic_cleanable
    before :each do
      ActiveElastic::ElasticSchema.force_create
    end
  end
end

Usage:

### spec/rails_helper.rb
....
RSpec.configure do |config|
  config.extend ElasticHelper
...

### /spec/some_spec.rb
describe SomeSpec do
  elastic_cleanble

  it do 
    ... 
  end
end

Refresh ElasticSearch index when creating updting a document.

Make sure to use Model.refresh_index! to access documents when created in test. Not using this will return nil when retreaving the created document.

....
it "this is a example" do
  FactoryGirl.create(:post)
  Post.refresh_index! # Without this command, the next search would return an empty list of posts.
  
  expect(Post.elastic_find.all.total).to eq(1)
end

Contributing

  1. Fork it ( https://github.com/PixelPerfectTree/active_elastic' )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

About

Active Record wrapper for ElasticSearch

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 99.7%
  • Shell 0.3%