class Searchkick::Results

Attributes

klass[R]
options[R]
response[R]

Public Class Methods

new(klass, response, options = {}) click to toggle source
# File lib/searchkick/results.rb, line 12
def initialize(klass, response, options = {})
  @klass = klass
  @response = response
  @options = options
end

Public Instance Methods

aggregations() click to toggle source
# File lib/searchkick/results.rb, line 77
def aggregations
  response["aggregations"]
end
aggs() click to toggle source
# File lib/searchkick/results.rb, line 81
def aggs
  @aggs ||= begin
    if aggregations
      aggregations.dup.each do |field, filtered_agg|
        buckets = filtered_agg[field]
        # move the buckets one level above into the field hash
        if buckets
          filtered_agg.delete(field)
          filtered_agg.merge!(buckets)
        end
      end
    end
  end
end
current_page() click to toggle source
# File lib/searchkick/results.rb, line 123
def current_page
  options[:page]
end
entry_name(options = {}) click to toggle source
# File lib/searchkick/results.rb, line 108
def entry_name(options = {})
  if options.empty?
    # backward compatibility
    model_name.human.downcase
  else
    default = options[:count] == 1 ? model_name.human : model_name.human.pluralize
    model_name.human(options.reverse_merge(default: default))
  end
end
error() click to toggle source
# File lib/searchkick/results.rb, line 100
def error
  response["error"]
end
first_page?() click to toggle source
# File lib/searchkick/results.rb, line 155
def first_page?
  previous_page.nil?
end
highlights(multiple: false) click to toggle source
# File lib/searchkick/results.rb, line 179
def highlights(multiple: false)
  hits.map do |hit|
    Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, multiple ? v : v.first] }]
  end
end
hits() click to toggle source
# File lib/searchkick/results.rb, line 167
def hits
  if error
    raise Searchkick::Error, "Query error - use the error method to view it"
  else
    @response["hits"]["hits"]
  end
end
last_page?() click to toggle source
# File lib/searchkick/results.rb, line 159
def last_page?
  next_page.nil?
end
limit_value()
Alias for: per_page
misspellings?() click to toggle source
# File lib/searchkick/results.rb, line 189
def misspellings?
  @options[:misspellings]
end
model_name() click to toggle source
# File lib/searchkick/results.rb, line 104
def model_name
  klass.model_name
end
next_page() click to toggle source
# File lib/searchkick/results.rb, line 151
def next_page
  current_page < total_pages ? (current_page + 1) : nil
end
num_pages()
Alias for: total_pages
offset()
Alias for: offset_value
offset_value() click to toggle source
# File lib/searchkick/results.rb, line 141
def offset_value
  (current_page - 1) * per_page + padding
end
Also aliased as: offset
out_of_range?() click to toggle source
# File lib/searchkick/results.rb, line 163
def out_of_range?
  current_page > total_pages
end
padding() click to toggle source
# File lib/searchkick/results.rb, line 132
def padding
  options[:padding]
end
per_page() click to toggle source
# File lib/searchkick/results.rb, line 127
def per_page
  options[:per_page]
end
Also aliased as: limit_value
prev_page()
Alias for: previous_page
previous_page() click to toggle source
# File lib/searchkick/results.rb, line 146
def previous_page
  current_page > 1 ? (current_page - 1) : nil
end
Also aliased as: prev_page
results() click to toggle source
# File lib/searchkick/results.rb, line 18
def results
  @results ||= begin
    if options[:load]
      # results can have different types
      results = {}

      hits.group_by { |hit, _| hit["_type"] }.each do |type, grouped_hits|
        klass = (!options[:index_name] && @klass) || type.camelize.constantize
        results[type] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s }
      end

      # sort
      hits.map do |hit|
        result = results[hit["_type"]][hit["_id"].to_s]
        if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
          if hit["highlight"] && !result.respond_to?(:search_highlights)
            highlights = Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, v.first] }]
            result.define_singleton_method(:search_highlights) do
              highlights
            end
          end
        end
        result
      end.compact
    else
      hits.map do |hit|
        result =
          if hit["_source"]
            hit.except("_source").merge(hit["_source"])
          elsif hit["fields"]
            hit.except("fields").merge(hit["fields"])
          else
            hit
          end

        if hit["highlight"]
          highlight = Hash[hit["highlight"].map { |k, v| [base_field(k), v.first] }]
          options[:highlighted_fields].map { |k| base_field(k) }.each do |k|
            result["highlighted_#{k}"] ||= (highlight[k] || result[k])
          end
        end

        result["id"] ||= result["_id"] # needed for legacy reasons
        HashWrapper.new(result)
      end
    end
  end
end
suggestions() click to toggle source
# File lib/searchkick/results.rb, line 67
def suggestions
  if response["suggest"]
    response["suggest"].values.flat_map { |v| v.first["options"] }.sort_by { |o| -o["score"] }.map { |o| o["text"] }.uniq
  elsif options[:term] == "*"
    []
  else
    raise "Pass `suggest: true` to the search method for suggestions"
  end
end
took() click to toggle source
# File lib/searchkick/results.rb, line 96
def took
  response["took"]
end
total_count() click to toggle source
# File lib/searchkick/results.rb, line 118
def total_count
  response["hits"]["total"]
end
Also aliased as: total_entries
total_entries()
Alias for: total_count
total_pages() click to toggle source
# File lib/searchkick/results.rb, line 136
def total_pages
  (total_count / per_page.to_f).ceil
end
Also aliased as: num_pages
with_highlights(multiple: false) click to toggle source
# File lib/searchkick/results.rb, line 185
def with_highlights(multiple: false)
  results.zip(highlights(multiple: multiple))
end
with_hit() click to toggle source
# File lib/searchkick/results.rb, line 175
def with_hit
  results.zip(hits)
end

Private Instance Methods

base_field(k) click to toggle source
# File lib/searchkick/results.rb, line 231
def base_field(k)
  k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "")
end
combine_includes(result, inc) click to toggle source
# File lib/searchkick/results.rb, line 221
def combine_includes(result, inc)
  if inc
    if inc.is_a?(Array)
      result.concat(inc)
    else
      result << inc
    end
  end
end
results_query(records, hits) click to toggle source
# File lib/searchkick/results.rb, line 195
def results_query(records, hits)
  ids = hits.map { |hit| hit["_id"] }
  if options[:includes] || options[:model_includes]
    included_relations = []
    combine_includes(included_relations, options[:includes])
    combine_includes(included_relations, options[:model_includes][records]) if options[:model_includes]

    records =
      if defined?(NoBrainer::Document) && records < NoBrainer::Document
        if Gem.loaded_specs["nobrainer"].version >= Gem::Version.new("0.21")
          records.eager_load(included_relations)
        else
          records.preload(included_relations)
        end
      else
        records.includes(included_relations)
      end
  end

  if options[:scope_results]
    records = options[:scope_results].call(records)
  end

  Searchkick.load_records(records, ids)
end