Restream/redmine_elasticsearch

View on GitHub
app/elastic/application_search.rb

Summary

Maintainability
A
0 mins
Test Coverage
module ApplicationSearch
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model

    index_name RedmineElasticsearch::INDEX_NAME

    after_commit :async_update_index
  end

  def to_indexed_json
    RedmineElasticsearch::SerializerService.serialize_to_json(self)
  end

  def async_update_index
    Workers::Indexer.defer(self)
  end

  module ClassMethods

    def index_mapping
      {
        document_type => {
          _parent: { type: 'parent_project' }
        }
      }
    end

    def additional_index_mappings
      return {} unless Rails.configuration.respond_to?(:additional_index_properties)
      Rails.configuration.additional_index_properties[self.name.tableize.to_sym] || {}
    end

    # Update mapping for document type
    def update_mapping
      __elasticsearch__.client.indices.put_mapping(
        index: index_name,
        type:  document_type,
        body:  index_mapping
      )
    end

    def allowed_to_search_query(user, options = {})
      options = options.merge(
        permission: :view_project,
        type:       document_type
      )
      ParentProject.allowed_to_search_query(user, options)
    end

    def searching_scope(project_id)
      self.where('project_id = ?', project_id)
    end

    # Import all records to elastic
    # @return [Integer] errors count
    def import(options = {}, &block)
      # Batch size for bulk operations
      batch_size = options.fetch(:batch_size, RedmineElasticsearch::BATCH_SIZE_FOR_IMPORT)

      # Document type
      type = options.fetch(:type, document_type)

      # Imported records counter
      imported = 0

      # Errors counter
      errors = 0

      find_in_batches(batch_size: batch_size) do |items|
        response = __elasticsearch__.client.bulk(
          index: index_name,
          type:  type,
          body:  items.map do |item|
            data   = item.to_indexed_json
            parent = data.delete :_parent
            { index: { _id: item.id, _parent: parent, data: data } }
          end
        )
        imported += items.length
        errors   += response['items'].map { |k, v| k.values.first['error'] }.compact.length

        # Call block with imported records count in batch
        yield(imported) if block_given?
      end
      errors
    end

    def remove_from_index(id)
      __elasticsearch__.client.delete index: index_name, type: document_type, id: id
    end
  end

  def update_index
    self.class.where(id: self.id).import
  end
end