Class: SearchFlip::Criteria

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Aggregatable, Customable, Explainable, Filterable, Highlightable, Paginatable, PostFilterable, Sortable, Sourceable
Defined in:
lib/search_flip/criteria.rb

Overview

The SearchFlip::Criteria class serves the purpose of chaining various filtering and aggregation methods. Each chainable method creates a new criteria object until a method is called that finally sends the respective request to Elasticsearch and returns the result.

Examples:

CommentIndex.where(public: true).sort(id: "desc").limit(1_000).records
CommentIndex.range(:created_at, lt: Time.parse("2014-01-01").delete
CommentIndex.search("hello world").total_entries
CommentIndex.query(more_like_this: { "...", fields: ["description"] })]
CommentIndex.exists(:user_id).paginate(page: 1, per_page: 100)
CommentIndex.sort("_doc").find_each { |comment| "..." }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Aggregatable

#aggregate, included

Methods included from PostFilterable

included, #post_exists, #post_exists_not, #post_filter, #post_must, #post_must_not, #post_range, #post_search, #post_should, #post_where, #post_where_not

Methods included from Filterable

#exists, #exists_not, #filter, included, #match_all, #must, #must_not, #range, #search, #should, #to_query, #where, #where_not

Methods included from Customable

#custom, included

Methods included from Paginatable

included, #limit, #limit_value_with_default, #offset, #offset_value_with_default, #page, #paginate, #per

Methods included from Explainable

#explain, included

Methods included from Highlightable

#highlight, included

Methods included from Sourceable

included, #source

Methods included from Sortable

included, #resort, #sort

Constructor Details

#initialize(attributes = {}) ⇒ Criteria

Creates a new SearchFlip::Criteria.

Parameters:

  • attributes (Hash) (defaults to: {})

    Attributes to initialize the Criteria with



183
184
185
186
187
# File 'lib/search_flip/criteria.rb', line 183

def initialize(attributes = {})
  attributes.each do |key, value|
    send "#{key}=", value
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



572
573
574
575
576
577
578
# File 'lib/search_flip/criteria.rb', line 572

def method_missing(name, *args, &block)
  if target.respond_to?(name)
    merge(target.send(name, *args, &block))
  else
    super
  end
end

Instance Attribute Details

#eager_load_valuesObject

Returns the value of attribute eager_load_values.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def eager_load_values
  @eager_load_values
end

#failsafe_valueObject

Returns the value of attribute failsafe_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def failsafe_value
  @failsafe_value
end

#includes_valuesObject

Returns the value of attribute includes_values.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def includes_values
  @includes_values
end

#preference_valueObject

Returns the value of attribute preference_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def preference_value
  @preference_value
end

#preload_valuesObject

Returns the value of attribute preload_values.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def preload_values
  @preload_values
end

#profile_valueObject

Returns the value of attribute profile_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def profile_value
  @profile_value
end

#routing_valueObject

Returns the value of attribute routing_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def routing_value
  @routing_value
end

#scroll_argsObject

Returns the value of attribute scroll_args.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def scroll_args
  @scroll_args
end

#search_type_valueObject

Returns the value of attribute search_type_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def search_type_value
  @search_type_value
end

#source_valueObject

Returns the value of attribute source_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def source_value
  @source_value
end

#suggest_valuesObject

Returns the value of attribute suggest_values.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def suggest_values
  @suggest_values
end

#targetObject

Returns the value of attribute target.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def target
  @target
end

#terminate_after_valueObject

Returns the value of attribute terminate_after_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def terminate_after_value
  @terminate_after_value
end

#timeout_valueObject

Returns the value of attribute timeout_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def timeout_value
  @timeout_value
end

#track_total_hits_valueObject

Returns the value of attribute track_total_hits_value.



27
28
29
# File 'lib/search_flip/criteria.rb', line 27

def track_total_hits_value
  @track_total_hits_value
end

Instance Method Details

#criteriaSearchFlip::Criteria Also known as: all

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Convenience method to have a unified conversion api.

Returns:



173
174
175
# File 'lib/search_flip/criteria.rb', line 173

def criteria
  self
end

#delete(params = {}) ⇒ Object

Sends a delete by query request to Elasticsearch, such that all documents matching the query get deleted. Please note, for certain Elasticsearch versions you need to install the delete-by-query plugin to get support for this feature. Refreshes the index if the auto_refresh is enabled. Raises SearchFlip::ResponseError in case any errors occur.

Examples:

CommentIndex.range(lt: Time.parse("2014-01-01")).delete
CommentIndex.where(public: false).delete

See Also:



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/search_flip/criteria.rb', line 328

def delete(params = {})
  dupped_request = request.dup
  dupped_request.delete(:from)
  dupped_request.delete(:size)

  if connection.version.to_i >= 5
    connection.http_client.post("#{target.type_url}/_delete_by_query", params: request_params.merge(params), json: dupped_request)
  else
    connection.http_client.delete("#{target.type_url}/_query", params: request_params.merge(params), json: dupped_request)
  end

  target.refresh if SearchFlip::Config[:auto_refresh]

  true
end

#eager_load(*args) ⇒ SearchFlip::Criteria

Specify associations of the target model you want to eager load via ActiveRecord’s or other ORM’s mechanisms when records get fetched from the database.

Examples:

CommentIndex.eager_load(:user, :post).records
PostIndex.eager_load(:comments => :user).records

Parameters:

  • args

    The args that get passed to the eager load method of ActiveRecord or other ORMs

Returns:



376
377
378
379
380
# File 'lib/search_flip/criteria.rb', line 376

def eager_load(*args)
  fresh.tap do |criteria|
    criteria.eager_load_values = (eager_load_values || []) + args
  end
end

#executeSearchFlip::Response Also known as: response

Executes the search request for the current criteria, ie sends the request to Elasticsearch and returns the response. Connection and response errors will be rescued if you specify the criteria to be #failsafe, such that an empty response is returned instead.

Examples:

response = CommentIndex.search("hello world").execute

Returns:



513
514
515
516
517
518
519
520
521
522
523
# File 'lib/search_flip/criteria.rb', line 513

def execute
  @response ||= begin
    Config[:instrumenter].instrument("request.search_flip", index: target, request: request) do |payload|
      response = execute!

      payload[:response] = response

      response
    end
  end
end

#failsafe(value) ⇒ SearchFlip::Response

Marks the criteria to be failsafe, ie certain exceptions raised due to invalid queries, inavailability of Elasticsearch, etc get rescued and an empty criteria is returned instead.

Examples:

CommentIndex.search("invalid/request").execute
# raises SearchFlip::ResponseError

# ...

CommentIndex.search("invalid/request").failsafe(true).execute
# => #<SearchFlip::Response ...>

Parameters:

  • value (Boolean)

    Whether or not the criteria should be failsafe

Returns:

See Also:



546
547
548
549
550
# File 'lib/search_flip/criteria.rb', line 546

def failsafe(value)
  fresh.tap do |criteria|
    criteria.failsafe_value = value
  end
end

#find_each(options = {}) ⇒ Object Also known as: each

Fetches the records specified by the relatin in batches using the Elasticsearch scroll API and yields each record. The batch size and scroll API timeout can be specified. Check out the Elasticsearch docs for further details.

Examples:

CommentIndex.search("hello world").find_each(batch_size: 100) do |record|
  # ...
end

Parameters:

  • options (Hash) (defaults to: {})

    The options to control the fetching of batches

Options Hash (options):

  • batch_size (Fixnum)

    The number of records to fetch per batch. Uses #limit to control the batch size.

  • timeout (String)

    The timeout per scroll request, ie how long Elasticsearch will keep the request handle open.



465
466
467
468
469
470
471
472
473
# File 'lib/search_flip/criteria.rb', line 465

def find_each(options = {})
  return enum_for(:find_each, options) unless block_given?

  find_in_batches options do |batch|
    batch.each do |record|
      yield record
    end
  end
end

#find_each_result(options = {}) ⇒ Object

Fetches the results specified by the criteria in batches using the Elasticsearch scroll API and yields each result. The batch size and scroll API timeout can be specified. Checkout out the Elasticsearch docs for further details.

Examples:

CommentIndex.search("hello world").find_each_result(batch_size: 100) do |result|
  # ...
end

Parameters:

  • options (Hash) (defaults to: {})

    The options to control the fetching of batches

Options Hash (options):

  • batch_size (Fixnum)

    The number of records to fetch per batch. Uses #limit to control the batch size.

  • timeout (String)

    The timeout per scroll request, ie how long Elasticsearch will keep the request handle open.



493
494
495
496
497
498
499
500
501
# File 'lib/search_flip/criteria.rb', line 493

def find_each_result(options = {})
  return enum_for(:find_each_result, options) unless block_given?

  find_results_in_batches options do |batch|
    batch.each do |result|
      yield result
    end
  end
end

#find_in_batches(options = {}) ⇒ Object

Fetches the records specified by the criteria in batches using the ElasicSearch scroll API and yields each batch. The batch size and scroll API timeout can be specified. Check out the Elasticsearch docs for further details.

Examples:

CommentIndex.search("hello world").find_in_batches(batch_size: 100) do |batch|
  # ...
end

Parameters:

  • options (Hash) (defaults to: {})

    The options to control the fetching of batches

Options Hash (options):

  • batch_size (Fixnum)

    The number of records to fetch per batch. Uses #limit to control the batch size.

  • timeout (String)

    The timeout per scroll request, ie how long Elasticsearch will keep the request handle open.



417
418
419
420
421
422
423
# File 'lib/search_flip/criteria.rb', line 417

def find_in_batches(options = {})
  return enum_for(:find_in_batches, options) unless block_given?

  yield_in_batches(options) do |criteria|
    yield(criteria.records) if criteria.records.size > 0
  end
end

#find_results_in_batches(options = {}) ⇒ Object

Fetches the results specified by the criteria in batches using the Elasticsearch scroll API and yields each batch. The batch size and scroll API timeout can be specified. Checkout out the Elasticsearch docs for further details.

Examples:

CommentIndex.search("hello world").find_results_in_batches(batch_size: 100) do |batch|
  # ...
end

Parameters:

  • options (Hash) (defaults to: {})

    The options to control the fetching of batches

Options Hash (options):

  • batch_size (Fixnum)

    The number of records to fetch per batch. Uses #limit to control the batch size.

  • timeout (String)

    The timeout per scroll request, ie how long Elasticsearch will keep the request handle open.



441
442
443
444
445
446
447
# File 'lib/search_flip/criteria.rb', line 441

def find_results_in_batches(options = {})
  return enum_for(:find_results_in_batches, options) unless block_given?

  yield_in_batches(options) do |criteria|
    yield criteria.results
  end
end

#freshSearchFlip::Response

Returns a fresh, ie dupped, criteria with the response cache being cleared.

Examples:

CommentIndex.search("hello world").fresh

Returns:



561
562
563
564
565
566
# File 'lib/search_flip/criteria.rb', line 561

def fresh
  dup.tap do |criteria|
    criteria.instance_variable_set(:@request, nil)
    criteria.instance_variable_set(:@response, nil)
  end
end

#includes(*args) ⇒ SearchFlip::Criteria

Specify associations of the target model you want to include via ActiveRecord’s or other ORM’s mechanisms when records get fetched from the database.

Examples:

CommentIndex.includes(:user, :post).records
PostIndex.includes(:comments => :user).records

Parameters:

  • args

    The args that get passed to the includes method of ActiveRecord or other ORMs

Returns:



357
358
359
360
361
# File 'lib/search_flip/criteria.rb', line 357

def includes(*args)
  fresh.tap do |criteria|
    criteria.includes_values = (includes_values || []) + args
  end
end

#merge(other) ⇒ SearchFlip::Criteria

Creates a new criteria while merging the attributes (constraints, settings, etc) of the current criteria with the attributes of another one passed as argument. For multi-value contstraints the resulting criteria will include constraints of both criterias. For single-value constraints, the values of the criteria passed as an argument are used.

Examples:

CommentIndex.where(approved: true).merge(CommentIndex.range(:created_at, gt: Time.parse("2015-01-01")))
CommentIndex.aggregate(:user_id).merge(CommentIndex.where(admin: true))

Returns:



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/search_flip/criteria.rb', line 43

def merge(other)
  other = other.criteria

  fresh.tap do |criteria|
    [
      :profile_value, :failsafe_value, :terminate_after_value, :timeout_value, :offset_value,
      :limit_value, :scroll_args, :source_value, :preference_value, :search_type_value,
      :routing_value, :track_total_hits_value, :explain_value
    ].each do |name|
      criteria.send(:"#{name}=", other.send(name)) unless other.send(name).nil?
    end

    [
      :sort_values, :includes_values, :preload_values, :eager_load_values, :must_values,
      :must_not_values, :filter_values, :post_must_values, :post_must_not_values,
      :post_filter_values
    ].each do |name|
      criteria.send(:"#{name}=", (criteria.send(name) || []) + other.send(name)) if other.send(name)
    end

    [:highlight_values, :suggest_values, :custom_value, :aggregation_values].each do |name|
      criteria.send(:"#{name}=", (criteria.send(name) || {}).merge(other.send(name))) if other.send(name)
    end
  end
end

#preference(value) ⇒ SearchFlip::Criteria

Specifies a preference value for the request. Check out the elasticsearch docs for further details.

Examples:

CommentIndex.preference("_primary")

Parameters:

  • value

    The preference value

Returns:



96
97
98
99
100
# File 'lib/search_flip/criteria.rb', line 96

def preference(value)
  fresh.tap do |criteria|
    criteria.preference_value = value
  end
end

#preload(*args) ⇒ SearchFlip::Criteria

Specify associations of the target model you want to preload via ActiveRecord’s or other ORM’s mechanisms when records get fetched from the database.

Examples:

CommentIndex.preload(:user, :post).records
PostIndex.includes(:comments => :user).records

Parameters:

  • args

    The args that get passed to the preload method of ActiveRecord or other ORMs

Returns:



395
396
397
398
399
# File 'lib/search_flip/criteria.rb', line 395

def preload(*args)
  fresh.tap do |criteria|
    criteria.preload_values = (preload_values || []) + args
  end
end

#profile(value) ⇒ SearchFlip::Criteria

Sets whether or not query profiling should be enabled.

Examples:

query = CommentIndex.profile(true)
query.raw_response["profile"] # => { "shards" => ... }

Parameters:

  • value (Boolean)

    Whether query profiling should be enabled or not

Returns:



284
285
286
287
288
# File 'lib/search_flip/criteria.rb', line 284

def profile(value)
  fresh.tap do |criteria|
    criteria.profile_value = value
  end
end

#requestHash

Generates the request object from the attributes specified via chaining, like eg offset, limit, query, filters, aggregations, etc and returns a Hash that later gets serialized as JSON.

Returns:

  • (Hash)

    The generated request object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/search_flip/criteria.rb', line 211

def request
  @request ||= begin
    res = {}

    if must_values || must_not_values || filter_values
      res[:query] = {
        bool: {
          must: must_values.to_a,
          must_not: must_not_values.to_a,
          filter: filter_values.to_a
        }.reject { |_, value| value.empty? }
      }
    end

    res.update(from: offset_value_with_default, size: limit_value_with_default)

    res[:track_total_hits] = track_total_hits_value unless track_total_hits_value.nil?
    res[:explain] = explain_value unless explain_value.nil?
    res[:timeout] = timeout_value if timeout_value
    res[:terminate_after] = terminate_after_value if terminate_after_value
    res[:highlight] = highlight_values if highlight_values
    res[:suggest] = suggest_values if suggest_values
    res[:sort] = sort_values if sort_values
    res[:aggregations] = aggregation_values if aggregation_values

    if post_must_values || post_must_not_values || post_filter_values
      res[:post_filter] = {
        bool: {
          must: post_must_values.to_a,
          must_not: post_must_not_values.to_a,
          filter: post_filter_values.to_a
        }.reject { |_, value| value.empty? }
      }
    end

    res[:_source] = source_value unless source_value.nil?
    res[:profile] = true if profile_value

    res.update(custom_value) if custom_value

    res
  end
end

#respond_to_missing?(name, *args) ⇒ Boolean

Returns:

  • (Boolean)


568
569
570
# File 'lib/search_flip/criteria.rb', line 568

def respond_to_missing?(name, *args)
  target.respond_to?(name, *args) || super
end

#routing(value) ⇒ SearchFlip::Criteria

Specifies the routing value for the request. Check out the elasticsearch docs for further details.

Examples:

CommentIndex.routing("user_id")

Parameters:

  • value

    The search type value

Returns:



128
129
130
131
132
# File 'lib/search_flip/criteria.rb', line 128

def routing(value)
  fresh.tap do |criteria|
    criteria.routing_value = value
  end
end

#scroll(id: nil, timeout: "1m") ⇒ SearchFlip::Criteria

Adds scrolling to the request with or without an already existing scroll id and using the specified timeout.

Examples:

query = CommentIndex.scroll(timeout: "5m")

until query.records.empty?
  # ...

  query = query.scroll(id: query.scroll_id, timeout: "5m")
end

Parameters:

  • id (String, nil) (defaults to: nil)

    The scroll id of the last request returned by SearchFlip or nil

  • timeout (String) (defaults to: "1m")

    The timeout of the scroll request, ie. how long SearchFlip should keep the scroll handle open

Returns:



310
311
312
313
314
# File 'lib/search_flip/criteria.rb', line 310

def scroll(id: nil, timeout: "1m")
  fresh.tap do |criteria|
    criteria.scroll_args = { id: id, timeout: timeout }
  end
end

#search_type(value) ⇒ SearchFlip::Criteria

Specifies the search type value for the request. Check out the elasticsearch docs for further details.

Examples:

CommentIndex.search_type("dfs_query_then_fetch")

Parameters:

  • value

    The search type value

Returns:



112
113
114
115
116
# File 'lib/search_flip/criteria.rb', line 112

def search_type(value)
  fresh.tap do |criteria|
    criteria.search_type_value = value
  end
end

#suggest(name, options = {}) ⇒ SearchFlip::Criteria

Adds a suggestion section with the given name to the request.

Examples:

query = CommentIndex.suggest(:suggestion, text: "helo", term: { field: "message" })
query.suggestions(:suggestion).first["text"] # => "hello"

Parameters:

  • name (String, Symbol)

    The name of the suggestion section

  • options (Hash) (defaults to: {})

    Additional suggestion options. Check out the Elasticsearch docs for further details.

Returns:



268
269
270
271
272
# File 'lib/search_flip/criteria.rb', line 268

def suggest(name, options = {})
  fresh.tap do |criteria|
    criteria.suggest_values = (criteria.suggest_values || {}).merge(name => options)
  end
end

#terminate_after(value) ⇒ SearchFlip::Criteria

Specifies early query termination, such that the processing will be stopped after the specified number of results has been accumulated.

Examples:

ProductIndex.terminate_after(10_000).search("hello world")

Parameters:

  • value (Fixnum)

    The number of records to terminate after

Returns:



161
162
163
164
165
# File 'lib/search_flip/criteria.rb', line 161

def terminate_after(value)
  fresh.tap do |criteria|
    criteria.terminate_after_value = value
  end
end

#timeout(value) ⇒ SearchFlip::Criteria

Specifies a query timeout, such that the processing will be stopped after that timeout and only the results calculated up to that point will be processed and returned.

Examples:

ProductIndex.timeout("3s").search("hello world")

Parameters:

  • value (String)

    The timeout value

Returns:



145
146
147
148
149
# File 'lib/search_flip/criteria.rb', line 145

def timeout(value)
  fresh.tap do |criteria|
    criteria.timeout_value = value
  end
end

#track_total_hits(value) ⇒ SearchFlip::Criteria

Specifies if or how many hits should be counted/tracked. Check out the elasticsearch docs for futher details.

Examples:

CommentIndex.track_total_hits(true)
CommentIndex.track_total_hits(10_000)

Parameters:

  • value

    The value for track_total_hits

Returns:



80
81
82
83
84
# File 'lib/search_flip/criteria.rb', line 80

def track_total_hits(value)
  fresh.tap do |criteria|
    criteria.track_total_hits_value = value
  end
end

#with_settingsSearchFlip::Criteria

Allows to set query specific settings like e.g. connection and index name. Please note, however, that this should only be used for special cases and the subsequent query can not be serialized. Checkout SearchFlip::Index.with_settings for more details.

Examples:

UserIndex.where("...").with_settings(connection: ProxyConnection)

Returns:



199
200
201
202
203
# File 'lib/search_flip/criteria.rb', line 199

ruby2_keywords def with_settings(*args)
  fresh.tap do |criteria|
    criteria.target = target.with_settings(*args)
  end
end