Elasticsearch::Model::TransactionalCallbacks
The elasticsearch-model
works great in simplifying the integration of Ruby classes ("models") with the
Elasticsearch search and analytics engine.
But, it come short with support for updating the indexed documents asynchronously.
Built-in support for updating the indexed documents comes in the form of Elasticsearch::Model::Callbacks
which will update each related document individually inside the same thread where the changes were made.
Depending on the size of your application, and the size of the changes themselves, triggering N number of
indexing requests to Elasticsearch could amount to nothing, or it could slow down the request-response
cycle considerably and render it unusable.
This gem aims to solve this by providing a way to update the index asynchronously via ActiveJob
.
Usage
The minimum is to include Elasticsearch::Model::TransactionalCallbacks
into any model
which could benefit from asynchronous indexing, e.g.
class User < ApplicationRecord
include Elasticsearch::Model
include Elasticsearch::Model::TransactionalCallbacks
index_name 'users'
document_type 'user'
mappings do
# indexes for users
end
end
But, this will end up trading n+1 on updating index with n+1 on database queries in case your #as_indexed_json
pulls data from associated models, e.g.
class Post < ApplicationRecord
include Elasticsearch::Model
include Elasticsearch::Model::TransactionalCallbacks
has_many :taggings, as: :taggable
has_many :tags, through: :taggings
index_name 'posts'
document_type 'post'
mappings dynamic: false do
indexes :subject, type: 'text', analyzer: 'english'
indexes :tags, type: 'keyword'
end
def as_indexed_json(_options = {})
{
subject: subject,
tags: tags.map(&:key) # FIXME: this triggers n+1 queries
}
end
end
to get around this, you can define a scope
called preload_for_import
like so:
class Post < ApplicationRecord
# ...snip...
scope :preload_for_import, -> { preload(:tags) }
# ...snip...
end
and it will be automatically called by the library.
Compatibility
This library is compatible and tested with Elasticsearch 5. Some work might be needed to make it work with Elasticsearch 6.
Installation
Add this line to your application's Gemfile:
gem 'elasticsearch-model-transactional_callbacks'
And then execute:
$ bundle
Or install it yourself as:
$ gem install elasticsearch-model-transactional_callbacks
Contributing
Any and all kinds of help are welcome! Especially interested in:
- sample use cases which are not yet supported
- compatibility with elasticsearch 6.0
Feel free to file an issue/PR with sample mapping!
License
The gem is available as open source under the terms of the MIT License.