I'm going to do elastic search on DoctorProfile and Subspeciality table. The error that I'm dealing with is that it gives the not found result. It takes a list of ids from doctor table but it doesn't gives desire result which is the doctor and with subspeciality. this is what everything that i did: I used these gems:
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-extensions', git: 'git://github.com/elasticsearch/elasticsearch-ruby.git'
my search method:
def search
query = params[:query]
#query.encode("UTF-8")
if query.nil?
render json: { message: "no query is provided" }, status: :unprocessable_entity
return
end
profiles = DoctorProfile.search(query).results.map { |r| r._source.id }
subspecialties = Subspecialty.search(query).results.map { |r| r._source.title }
subspecialties.uniq!
profiles = profiles + DoctorProfile.where("subspeciality in (?)", subspecialties).ids
profiles.uniq!
logger.info "################ The profile is #{profiles} ########################"
@doctors = DoctorProfile.find(profiles)
@cleaned_doctors = @doctors.select { |u| !u.user.nil? }
render json: @cleaned_doctors
end
in the doctor model:
after_commit on: [:create] do
__elasticsearch__.index_document if self.enabled?
end
after_commit on: [:update] do
__elasticsearch__.update_document if self.enabled?
end
after_commit on: [:destroy] do
__elasticsearch__.delete_document
end
settings index: {
number_of_shards: 1,
number_of_replicas: 0,
analysis: {
filter: {
autocomplete_filter: {
type: "edge_ngram",
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: "custom",
tokenizer: "standard",
filter: [
"lowercase",
"autocomplete_filter"
]
}
}
}
}
mappings dynamic: 'false' do
indexes :first_name, type: "string"
indexes :last_name, type: "string"
indexes :medical_code, type: "string"
indexes :expertise, type: "string", analyzer: "autocomplete", search_analyzer: "standard"
indexes :subspeciality, type: "string", analyzer: "autocomplete", search_analyzer: "standard"
end
def self.search(query)
__elasticsearch__.search(
{
query: {
multi_match: {
query: query,
fields: ['medical_code^10', 'subspeciality^5', 'expertise^2', 'first_name', 'last_name']
}
}
}
)
and in subspeciality model:
after_commit on: [:create] do
self.services = self.services.each {|str| str.force_encoding("UTF-8")}
__elasticsearch__.index_document if self.enabled?
end
after_commit on: [:update] do
self.services = self.services.each {|str| str.force_encoding("UTF-8")}
__elasticsearch__.update_document if self.enabled?
end
after_commit on: [:destroy] do
__elasticsearch__.delete_document
end
settings index: {
number_of_shards: 1,
number_of_replicas: 0,
analysis: {
filter: {
autocomplete_filter: {
type: "edge_ngram",
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: "custom",
tokenizer: "standard",
filter: [
"lowercase",
"autocomplete_filter"
]
}
}
}
}
mappings dynamic: 'false' do
indexes :description, type: "string", analyzer: "autocomplete", search_analyzer: "standard"
indexes :services, type: "string"
end
def self.search(query)
__elasticsearch__.search(
{
query: {
multi_match: {
query: query,
fields: ['description', 'services']
}
}
}
)
end
and this is my error in log :
Couldn't find all DoctorProfiles with 'id': (031addd8-9df8-4a53-974d-da0067302ad0, ff890720-4bfb-47d8-bdb8-3dc712b27f29, 869b28e1-cdd7-4bb6-b1d0-c7296e4b0637, 6dd6a784-c54b-4bb7-a0e1-337474ec4114, 234ccc87-f0c7-42f7-b96f-cf8d85487929, 543b621d-87aa-4a34-b6d6-62144c6a387e, 77e35144-9b93-48a0-a5bb-7b3addb99dff, d368f1df-3d1a-49ce-b6f5-f791df3294b1, d3dca8de-3143-4b03-90ec-e73a27c88960, 24abb0b3-2d11-457b-b95d-972462c4a37f) (found 2 results, but was looking for 10
i changed this line of code
@doctors = DoctorProfile.find(profiles)
to
@doctors = DoctorProfile.where("id in (?)",profiles)
and remove this line:
@cleaned_doctors = @doctors.select { |u| !u.user.nil? }
now i want to know what does this method do eactly.
@cleaned_doctors = @doctors.select { |u| !u.user.nil? }
to be mention, i have a table named user that doctorProfile has reference to it
Your code doesn't say much, but it seems that you have a boolean enabled
on your model, which tells whether the record is to be indexed or not.
The issue is with the update callback, because if you change your model from enabled
to not enabled
, instead of removing it from the index, it just don't update existing information.
The correct callback would be
after_commit on: [:update] do
if enabled?
if previous_changes['enabled'] &&
!previous_changes['enabled'].first
# previously not enabled, we need to index it
__elasticsearch__.index_document
else
# previously enabled, we need to update it
__elasticsearch__.update_document
end
else
# not enabled
if previous_changes['enabled'] &&
previous_changes['enabled'].first
# previously enabled, delete
__elasticsearch__.delete_document
end
# if it wasn't enabled before, it's not in the index anyway.
# do nothing
end
end
The previous_changes
hash stores the attributes that did change when saving the model, so you can check the previous value of the enabled
attribute. See http://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-previous_changes
Once you have the new callback in place, rebuild the indexes to remove the bogus data in production if needed:
DoctorProfile.where(enabled: true).find_each { |dp| dp.__elasticsearch__.index_document }
Subspecialty.where(enabled: true).find_each { |dp| dp.__elasticsearch__.index_document }