def search(*arguments)
      start_t = Time.now

      arguments = normalized_search_arguments(*arguments)

      results = search_implementation(arguments)

      fill_in_search_metadata_for(results, arguments)

      results.timing = (Time.now - start_t)

      return results
    rescue *auto_rescue_exceptions => e
      # Uncaught exception, log and turn into failed Results object. We
      # only catch certain types of exceptions, or it makes dev really
      # confusing eating exceptions. This is intentionally a convenience
      # to allow search engine implementations to just raise the exception
      # and we'll turn it into a proper error.
      cleaned_backtrace = Rails.backtrace_cleaner.clean(e.backtrace)
      log_msg = "BentoSearch::SearchEngine failed results: #{e.inspect}\n    #{cleaned_backtrace.join("\n    ")}"
      Rails.logger.error log_msg

      failed = BentoSearch::Results.new
      failed.error ||= {}
      failed.error[:exception] = e

      failed.timing                = (Time.now - start_t)

      fill_in_search_metadata_for(failed, arguments)

      return failed
    ensure
      if results && configuration.log_failed_results && results.failed?
        Rails.logger.error("Error fetching results for `#{configuration.id || self}`: #{arguments}: #{results.error}")
      end
    end
def search(*arguments)
      start_t = Time.now

      arguments = normalized_search_arguments(*arguments)

      results = search_implementation(arguments)

      fill_in_search_metadata_for(results, arguments)

      results.timing = (Time.now - start_t)

      return results
    rescue *auto_rescue_exceptions => e
      # Uncaught exception, log and turn into failed Results object. We
      # only catch certain types of exceptions, or it makes dev really
      # confusing eating exceptions. This is intentionally a convenience
      # to allow search engine implementations to just raise the exception
      # and we'll turn it into a proper error.
      cleaned_backtrace = Rails.backtrace_cleaner.clean(e.backtrace)
      log_msg = "BentoSearch::SearchEngine failed results: #{e.inspect}\n    #{cleaned_backtrace.join("\n    ")}"
      Rails.logger.error log_msg

      failed = BentoSearch::Results.new
      failed.error ||= {}
      failed.error[:exception] = e

      failed.timing                = (Time.now - start_t)

      fill_in_search_metadata_for(failed, arguments)

      return failed
    ensure
      if results && configuration.log_failed_results && results.failed?
        Rails.logger.error("Error fetching results for `#{configuration.id || self}`: #{arguments}: #{results.error}")
      end
    end
If specific SearchEngine calls initialize, you want to call super
 handles configuration loading, mostly. Argument is a
 Confstruct::Configuration or Hash.
 Method used to actually get results from a search engine.

 When implementing a search engine, you do not override this #search
 method, but instead override #search_implementation. #search will
 call your specific #search_implementation, first normalizing the query
 arguments, and then normalizing and adding standard metadata to your return value.

  Most engines support pagination, sorting, and searching in a specific
  field.

      # 1-based page index
      engine.search("query", :per_page => 20, :page => 5)
      # or use 0-based per-record index, engines that don't
      # support this will round to nearest page.
      engine.search("query", :start => 20)

  You can ask an engine what search fields it supports with engine.search_keys
      engine.search("query", :search_field => "engine_search_field_name")

  There are also normalized 'semantic' names you can use accross engines
  (if they support them): :title, :author, :subject, maybe more.

      engine.search("query", :semantic_search_field => :title)

  Ask an engine what semantic field names it supports with `engine.semantic_search_keys`

  Unrecognized search fields will be ignored, unless you pass in
  :unrecognized_search_field => :raise (or do same in config).

  Ask an engine what sort fields it supports with `engine.sort_keys`. See
  list of standard sort keys in I18n file at ./config/locales/en.yml, in
  `en.bento_search.sort_keys`.

      engine.search("query", :sort => "some_sort_key")

  Some engines support additional arguments to 'search', see individual
  engine documentation. For instance, some engines support `:auth => true`
  to give the user elevated search privileges when you have an authenticated
  local user.

 Query as first arg is just a convenience, you can also use a single hash
 argument.

      engine.search(:query => "query", :per_page => 20, :page => 4)