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, #match_none, #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



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

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



594
595
596
597
598
599
600
# File 'lib/search_flip/criteria.rb', line 594

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

#http_timeout_valueObject

Returns the value of attribute http_timeout_value.



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

def http_timeout_value
  @http_timeout_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:



190
191
192
# File 'lib/search_flip/criteria.rb', line 190

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:



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/search_flip/criteria.rb', line 345

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

  http_request = connection.http_client
  http_request = http_request.timeout(http_timeout_value) if http_timeout_value

  if connection.version.to_i >= 5
    url = connection.version.to_i < 8 ? target.type_url : target.index_url

    http_request.post("#{url}/_delete_by_query", params: request_params.merge(params), json: dupped_request)
  else
    http_request.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:



398
399
400
401
402
# File 'lib/search_flip/criteria.rb', line 398

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, timeout 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:



535
536
537
538
539
540
541
542
543
544
545
# File 'lib/search_flip/criteria.rb', line 535

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:



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

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.



487
488
489
490
491
492
493
494
495
# File 'lib/search_flip/criteria.rb', line 487

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.



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

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.



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

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.



463
464
465
466
467
468
469
# File 'lib/search_flip/criteria.rb', line 463

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:



583
584
585
586
587
588
# File 'lib/search_flip/criteria.rb', line 583

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

#http_timeout(value) ⇒ SearchFlip::Criteria

Specifies a http timeout, such that a SearchFlip::TimeoutError will be thrown when the request times out.

Examples:

ProductIndex.http_timeout(3).search("hello world")

Parameters:

  • value (Fixnum)

    The timeout value

Returns:



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

def http_timeout(value)
  fresh.tap do |criteria|
    criteria.http_timeout_value = value
  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:



379
380
381
382
383
# File 'lib/search_flip/criteria.rb', line 379

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:



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

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, :http_timeout_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:



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

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:



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

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:



301
302
303
304
305
# File 'lib/search_flip/criteria.rb', line 301

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



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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/search_flip/criteria.rb', line 228

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)


590
591
592
# File 'lib/search_flip/criteria.rb', line 590

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:



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

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:



327
328
329
330
331
# File 'lib/search_flip/criteria.rb', line 327

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:



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

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:



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

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:



178
179
180
181
182
# File 'lib/search_flip/criteria.rb', line 178

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:



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

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:



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

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:



216
217
218
219
220
# File 'lib/search_flip/criteria.rb', line 216

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