Elasticsearch::Model - Put Mapping
The PUT mapping API allows you to add fields to an existing index. This method is available with Elasticsearch::Model but it’s not documented.
Elasticsearch Version - 5.3
Create a User model
> rails g model user first_name:string last_name:string email:string phone_number:string
invoke active_record
create db/migrate/20180420162454_create_users.rb
create app/models/user.rb
> rake db:migrate
Seed the data
10.times do
name = Faker::Name.first_name
User.create!(
first_name: name,
last_name: Faker::Name.last_name,
email: Faker::Internet.email(name),
phone_number: Faker::PhoneNumber.phone_number
)
end
Add mapping
# app/models/concerns/searchable.rb
module Searchable
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
mapping do
indexes :id, type: :integer
indexes :first_name, type: :text
indexes :last_name, type: :text
indexes :email, type: :text
end
end
end
#app/models/user.rb
class User < ActiveRecord::Base
include Searchable
def as_indexed_json(_options = {})
as_json(only: %i[id first_name last_name email phone_number])
end
end
Create index and import all users
> User.__elasticsearch__.create_index!
{
"acknowledged" => true,
"shards_acknowledged" => true,
"index" => "users"
}
> User.import
You can search users now
> response = User.search 'vesta'
> response.results.as_json
[
{
"_index" => "users",
"_type" => "user",
"_id" => "10",
"_score" => 1.6348188,
"_source" => {
"id" => 10,
"first_name" => "Vesta",
"last_name" => "Toy",
"email" => "vesta@bradtkeconnelly.biz"
}
}
]
Add new fields
Now to change the mapping just add new field and update the mapping
mapping do
#...
indexes :phone_number, type: :text
end
Update the mapping using Put Mapping API
class User < ActiveRecord::Base
# ...
def self.put_mapping
__elasticsearch__.client.indices.put_mapping(
index: index_name,
type: document_type,
body: mapping.to_hash
)
end
end
Bulk Update
Now you need to update all the documents. we can use the bulk update API.
def self.bulk_update
find_in_batches do |users|
__elasticsearch__.client.bulk(
index: index_name,
type: __elasticsearch__.document_type,
body: processed_records(users)
)
end
end
def self.processed_records(users)
users.map do |user|
{
update: {
_id: user.id,
data: {
doc: {
id: user.id,
phone_number: user.phone_number
}.as_json
}
}
}
end
end