Introduction¶ ↑
ElasticsearchRails DynamicJsonSupport - Small little change to help your model update easier in elasticsearch.
Problem it solved¶ ↑
In ElasicSearch, if you define your model the following way:
# app/models/article.rb class Article < ActiveRecord::Base include Elasticsearch::Model include Elasticsearch::Model::Callbacks has_many :reviews def as_indexed_json options={} { id: id, title: title, article: content, created_at: created_at, updated_at: updated_at, reviews: reviews.map(&:as_json), } end # app/models/review.rb class Review < ActiveRecord::Base belongs_to :article end
There're 2 issues with the implementation above:
-
when the
content
is updated, this change would never be synced to the thearticle
field in ElasticSearch, since the key isartile
instead -
when the corresponding review is updated, the
article
is never updated, since it's not awared of the change.
This library aims to solve these 2 issues, with the following convention:
-
es_json_changes(changed_attributes)
- for a given set of changed attributes, it would response with the update to be processed by this record -
Elasticsearch::Model::CascadeUpdate
- class, when included, providing: -
class methods:
-
es_register_attributes { key => lambda }
: to register a hash ofkey, lambda
pairs, to be used for rendering the json. if lambda is nil, default to the public method of this resource namedkey
. -
key_name, relationship_name: nil, reverse_relationship_name: nil, &blk
: to register an association of key, lambda. relationship_name default to key if not given, and reverse_relationship_name default to the singular form of the class name if not given. After this registration, whenever the corresponding resource is updated, it would trigger this resource (which is related to the resource) to update.
-
Example usage (which solves the 2 issues above) is as given below:
# app/models/article.rb class Article < ActiveRecord::Base include Elasticsearch::Model include Elasticsearch::Model::Callbacks include Elasticsearch::Model::CascadeUpdate has_many :reviews es_register_attributes :id, :title, article: lambda {|rec| rec.content } # silent attribute would not be output by default es_register_silent_attributes :created_at, :updated_at # register association, with: # - key_name = :reviews # - get_assoc: default to be `#reviews` (the key_name) # - &blk: the render_assoc, default to be: `object#as_indexed_json`. # it would use a `map` by default for the has_many relationships # - reverse_class: default to guess from the relationship # - reverse_trigger: lambda {|obj, changes| do_things } # the reverse_trigger, when the model change, to render the json # document and update the objects. the returns is an array of the # original object to be updated es_register_assoc(:reviews) { |review| review.as_indexed_json } # for the given changed_attributes, it would return the json to be fed # into the `#update_document` method. What's given here is the default # behaviour -- which is to find the keys, and do a matching def elasticsearch_json_changes(changed_attributes) keys_to_update = changed_attributes.keys.map {|k| key_map k} self.as_indexed_json.select { |k,_| keys_to_update.include? k.to_s } end private def key_map(key) key = key.to_s case key when 'content' 'article' else key end end end # app/models/review.rb class Review < ActiveRecord::Base # Make sure to register Article Article belongs_to :article def as_indexed_json(options = {}) as_json end end
More features¶ ↑
-
Exclusion of keys: simply call
record.as_indexed_json: exclude_keys: %w[keys you do not like]
. -
Selective Import:
es_to_json_when(scope_name, &condition_check_block)
. if the scope_name is not given, it would import all by default.condition_check_block
is for checking before making the import
ToDos¶ ↑
-
[ ] Tests.. since I don't have time to write test case for this project yet.
-
[ ] Due to the
lazy-loading
of model in rails, you need to specifically specify the model in rails. Like in theReview
class above, it's reference toArticle
(to make sure thatArticle
class is loaded beforeReview
) -
[ ] Auto generation of mapping
Contributing to elasticsearch-rails-dynamic-json-support¶ ↑
-
Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
-
Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
-
Fork the project.
-
Start a feature/bugfix branch.
-
Commit and push until you are happy with your contribution.
-
Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
-
Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright¶ ↑
Copyright © 2016 Song Yangyu. See LICENSE.txt for further details.