Search code examples
ruby-on-railsrubyelasticsearchelasticsearch-rails

elastic search not found error in ruby on rails


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


Solution

  • 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 }