class Trample::Search
Attributes
_aggs[RW]
_conditions[RW]
_models[R]
Public Class Methods
aggregation(name, attrs = {}) { |_aggs| ... }
click to toggle source
# File lib/trample/search.rb, line 31 def self.aggregation(name, attrs = {}) attrs.merge!(name: name) attrs[:order] = @_aggs.keys.length @_aggs[name] = Aggregation.new(attrs) yield @_aggs[name] if block_given? end
condition(name, attrs = {})
click to toggle source
# File lib/trample/search.rb, line 25 def self.condition(name, attrs = {}) attrs.merge!(name: name, search_klass: self) @_conditions[name] = Condition.new(attrs) end
inherited(klass)
click to toggle source
Calls superclass method
# File lib/trample/search.rb, line 19 def self.inherited(klass) super klass._conditions = self._conditions.dup klass._aggs = self._aggs.dup end
model(*klasses)
click to toggle source
# File lib/trample/search.rb, line 38 def self.model(*klasses) @_models = klasses end
paginate(page_params)
click to toggle source
# File lib/trample/search.rb, line 42 def self.paginate(page_params) instance = new instance.paginate(page_params) end
Public Instance Methods
agg(*names_or_payloads)
click to toggle source
todo refactor…
# File lib/trample/search.rb, line 88 def agg(*names_or_payloads) names_or_payloads.each do |name_or_payload| name = name_or_payload selections = [] if name_or_payload.is_a?(Hash) name = name_or_payload.keys.first if name_or_payload.is_a?(Hash) selections = Array(name_or_payload.values.first) end template = self.class._aggs[name.to_sym] raise AggregationNotDefinedError.new(self, name) unless template agg = self.aggregations.find { |a| a.name.to_sym == name.to_sym } if agg.nil? # N.B. deep dup so buckets don't mutate agg = Aggregation.new(deep_dup(template.attributes).merge(name: name.to_sym)) agg.bucket_sort = template.bucket_sort self.aggregations << agg end selections.each do |key| bucket = agg.find_or_initialize_bucket(key) bucket.selected = true end end self end
aggregations()
click to toggle source
# File lib/trample/search.rb, line 131 def aggregations @aggregations.sort! { |a, b| a.order <=> b.order } @aggregations end
aggregations=(aggregation_array)
click to toggle source
N.B rails may send nil here instead of empty array
Calls superclass method
# File lib/trample/search.rb, line 117 def aggregations=(aggregation_array) aggregation_array ||= [] super([]) aggregation_array.each do |aggregation_hash| if aggregation_hash[:buckets] # rails converting [] to nil selections = aggregation_hash[:buckets].select { |b| !!b[:selected] }.map { |b| b[:key] } agg(aggregation_hash[:name].to_sym => selections) else agg(aggregation_hash[:name].to_sym => []) end end end
backend()
click to toggle source
# File lib/trample/search.rb, line 143 def backend @backend ||= Backend::Searchkick.new(metadata, self.class._models) end
condition(name)
click to toggle source
# File lib/trample/search.rb, line 79 def condition(name) ConditionProxy.new(name, self) end
conditions=(hash)
click to toggle source
Calls superclass method
# File lib/trample/search.rb, line 136 def conditions=(hash) super({}) hash.each_pair do |name, value| condition(name).set(value) end end
find_in_batches(batch_size: 10_000) { |results| ... }
click to toggle source
Uses elasticsearch scroll, as ES will blow up > 10_000 results, even if you are paginating.
-
Execute a search, telling ES we are scrolling
-
metadata.scroll_id is set on response
-
Use the scroll_id to fetch the next resultset
-
Repeat until results are exhausted
# File lib/trample/search.rb, line 191 def find_in_batches(batch_size: 10_000) metadata.scroll = true metadata.pagination.per_page = batch_size query! while !self.results.empty? yield self.results query! end self.metadata = Metadata.new end
includes(includes)
click to toggle source
# File lib/trample/search.rb, line 83 def includes(includes) self.metadata.records[:includes] = includes end
page(current_page)
click to toggle source
# File lib/trample/search.rb, line 54 def page(current_page) metadata.pagination.current_page = current_page self end
paginate(page_params)
click to toggle source
# File lib/trample/search.rb, line 47 def paginate(page_params) page_params ||= {} metadata.pagination.current_page = page_params[:number] if page_params[:number] metadata.pagination.per_page = page_params[:size] if page_params[:size] self end
per(per_page)
click to toggle source
# File lib/trample/search.rb, line 59 def per(per_page) metadata.pagination.per_page = per_page self end
query!(options = { lookup: true })
click to toggle source
# File lib/trample/search.rb, line 147 def query!(options = { lookup: true }) @records = nil hash = backend.query!(conditions, aggregations) load_autocompletes if options[:lookup] self.metadata.took = hash[:took] self.metadata.scroll_id = hash[:scroll_id] self.metadata.pagination.total = hash[:total] self.results = hash[:results] if !!metadata.records[:load] records! else self.results end end
records()
click to toggle source
Todo only works for single-model search atm N.B. preserves sorting
# File lib/trample/search.rb, line 166 def records @records ||= begin queried = self.class._models.first.where(id: results.map(&:_id)) queried = queried.includes(metadata.records[:includes]) [].tap do |sorted| results.each do |result| model = queried.find { |m| m.id.to_s == result.id.to_s } sorted << model end end end end
records!()
click to toggle source
# File lib/trample/search.rb, line 179 def records! @records = nil records end
sort(*fields)
click to toggle source
# File lib/trample/search.rb, line 64 def sort(*fields) return self if fields.empty? sorts = fields.map do |f| if f.to_s.starts_with?('-') f.sub!('-','') {att: f, dir: :desc} else {att: f, dir: :asc} end end self.metadata.sort = sorts self end
Private Instance Methods
deep_dup(o)
click to toggle source
# File lib/trample/search.rb, line 204 def deep_dup(o) Marshal.load(Marshal.dump(o)) end
load_autocompletes()
click to toggle source
# File lib/trample/search.rb, line 208 def load_autocompletes self.conditions.values.each(&:lookup_autocomplete) end