Class: ElasticSearch::Relation

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
AggregatableRelation, FilterableRelation, PostFilterableRelation
Defined in:
lib/elastic_search/relation.rb

Overview

The ElasticSearch::Relation class serves the purpose of chaining various filtering and aggregation methods. Each chainable method creates a new relation object until a method is called that finally sends the respective request to ElasticSearch and then the result is returned.

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 AggregatableRelation

#aggregate, included

Methods included from PostFilterableRelation

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 FilterableRelation

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

Constructor Details

#initialize(attributes = {}) ⇒ Relation

Creates a new ElasticSearch::Relation.

Parameters:

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

    Attributes to initialize the Relation with



142
143
144
145
146
# File 'lib/elastic_search/relation.rb', line 142

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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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



725
726
727
728
729
730
731
# File 'lib/elastic_search/relation.rb', line 725

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

Instance Attribute Details

#custom_valueObject

Returns the value of attribute custom_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def custom_value
  @custom_value
end

#eager_load_valuesObject

Returns the value of attribute eager_load_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def eager_load_values
  @eager_load_values
end

#failsafe_valueObject

Returns the value of attribute failsafe_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def failsafe_value
  @failsafe_value
end

#highlight_valuesObject

Returns the value of attribute highlight_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def highlight_values
  @highlight_values
end

#includes_valuesObject

Returns the value of attribute includes_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def includes_values
  @includes_values
end

#limit_valueObject

Returns the value of attribute limit_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def limit_value
  @limit_value
end

#offset_valueObject

Returns the value of attribute offset_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def offset_value
  @offset_value
end

#preload_valuesObject

Returns the value of attribute preload_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def preload_values
  @preload_values
end

#profile_valueObject

Returns the value of attribute profile_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def profile_value
  @profile_value
end

#scroll_argsObject

Returns the value of attribute scroll_args



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def scroll_args
  @scroll_args
end

#sort_valuesObject

Returns the value of attribute sort_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def sort_values
  @sort_values
end

#source_valueObject

Returns the value of attribute source_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def source_value
  @source_value
end

#suggest_valuesObject

Returns the value of attribute suggest_values



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def suggest_values
  @suggest_values
end

#targetObject

Returns the value of attribute target



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def target
  @target
end

#terminate_after_valueObject

Returns the value of attribute terminate_after_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def terminate_after_value
  @terminate_after_value
end

#timeout_valueObject

Returns the value of attribute timeout_value



22
23
24
# File 'lib/elastic_search/relation.rb', line 22

def timeout_value
  @timeout_value
end

Instance Method Details

#custom(hash) ⇒ ElasticSearch::Relation

Note:

Use with caution, because using #custom will potentiall override other sections like aggregations, query, sort, etc if you use the the same section names.

Adds a fully custom field/section to the request, such that upcoming or minor ElasticSearch features as well as other custom requirements can be used without having yet specialized relation methods.

Examples:

CommentIndex.custom(section: { argument: "value" }).request
=> {:section=>{:argument=>"value"},...}

Parameters:

  • hash (Hash)

    The custom section that is added to the request

Returns:



495
496
497
498
499
# File 'lib/elastic_search/relation.rb', line 495

def custom(hash)
  fresh.tap do |relation|
    relation.custom_value = (custom_value || {}).merge(hash)
  end
end

#deleteObject

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 ElasticSearch::ResponseError in case any errors occur.

Examples:

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

See Also:



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/elastic_search/relation.rb', line 333

def delete
  _request = request.dup
  _request.delete(:from)
  _request.delete(:size)

  if ElasticSearch.version.to_i >= 5
    ElasticSearch::HTTPClient.post("#{target.type_url}/_delete_by_query", json: _request)
  else
    ElasticSearch::HTTPClient.delete("#{target.type_url}/_query", json: _request)
  end

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

  true
end

#eager_load(*args) ⇒ ElasticSearch::Relation

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:



397
398
399
400
401
# File 'lib/elastic_search/relation.rb', line 397

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

#execute(base_url: target.base_url) ⇒ ElasticSearch::Response Also known as: response

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

Examples:

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

Parameters:

  • base_url

    An optional alternative base_url to send the request to for e.g. proxying

Returns:



654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
# File 'lib/elastic_search/relation.rb', line 654

def execute(base_url: target.base_url)
  @response ||= begin
    http_request = ElasticSearch::HTTPClient.headers(accept: "application/json")

    http_response =
      if scroll_args && scroll_args[:id]
        if ElasticSearch.version.to_i >= 2
          http_request.post("#{base_url}/_search/scroll", json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] })
        else
          http_request.headers(content_type: "text/plain").post("#{base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
        end
      elsif scroll_args
        http_request.post("#{target.type_url(base_url: base_url)}/_search", params: { scroll: scroll_args[:timeout] }, json: request)
      else
        http_request.post("#{target.type_url(base_url: base_url)}/_search", json: request)
      end

    ElasticSearch::Response.new(self, http_response.parse)
  rescue ElasticSearch::ConnectionError, ElasticSearch::ResponseError => e
    raise e unless failsafe_value

    ElasticSearch::Response.new(self, "took" => 0, "hits" => { "total" => 0, "hits" => [] })
  end
end

#failsafe(value) ⇒ ElasticSearch::Response

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

Examples:

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

# ...

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

Parameters:

  • value (Boolean)

    Whether or not the relation should be failsafe

Returns:

See Also:



700
701
702
703
704
# File 'lib/elastic_search/relation.rb', line 700

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

#find_each(options = {}) ⇒ ElasticSearch::Relation 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.

Returns:



629
630
631
632
633
634
635
636
637
# File 'lib/elastic_search/relation.rb', line 629

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_in_batches(options = {}) ⇒ ElasticSearch::Relation

Fetches the records specified by the relation 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.

Returns:



596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/elastic_search/relation.rb', line 596

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

  batch_size = options[:batch_size] || 1_000
  timeout = options[:timeout] || "1m"

  relation = limit(batch_size).scroll(timeout: timeout)

  until relation.records.empty?
    yield relation.records

    relation = relation.scroll(id: relation.scroll_id, timeout: timeout)
  end
end

#freshElasticSearch::Response

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

Examples:

CommentIndex.search("hello world").fresh

Returns:



715
716
717
718
719
# File 'lib/elastic_search/relation.rb', line 715

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

#highlight(fields, options = {}) ⇒ ElasticSearch::Relation

Adds highlighting of the given fields to the request.

Examples:

CommentIndex.highlight([:title, :message])
CommentIndex.highlight(:title).highlight(:description)
CommentIndex.highlight(:title, require_field_match: false)
CommentIndex.highlight(title: { type: "fvh" })
query = CommentIndex.highlight(:title).search("hello")
query.results[0].highlight.title # => "<em>hello</em> world"

Parameters:

  • fields (Hash, Array, String, Symbol)

    The fields to highligt. Supports raw ElasticSearch values by passing a Hash.

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

    Extra highlighting options. Check out the ElasticSearch docs for further details.

Returns:



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/elastic_search/relation.rb', line 244

def highlight(fields, options = {})
  fresh.tap do |relation|
    relation.highlight_values = (relation.highlight_values || {}).merge(options)

    hash = if fields.is_a?(Hash)
      fields
    elsif fields.is_a?(Array)
      fields.each_with_object({}) { |field, h| h[field] = {} }
    else
      { fields => {} }
    end

    relation.highlight_values[:fields] = (relation.highlight_values[:fields] || {}).merge(hash)
  end
end

#includes(*args) ⇒ ElasticSearch::Relation

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:



378
379
380
381
382
# File 'lib/elastic_search/relation.rb', line 378

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

#limit(n) ⇒ ElasticSearch::Relation

Sets the request limit, ie ElasticSearch's size parameter that is used to restrict the results that get returned.

Examples:

CommentIndex.limit(100)

Parameters:

  • n (Fixnum)

    The limit value, ie the max number of results that should be returned

Returns:



537
538
539
540
541
# File 'lib/elastic_search/relation.rb', line 537

def limit(n)
  fresh.tap do |relation|
    relation.limit_value = n.to_i
  end
end

#limit_value_with_defaultFixnum

Returns the limit value or, if not yet set, the default limit value (30).

Returns:

  • (Fixnum)

    The limit value



547
548
549
# File 'lib/elastic_search/relation.rb', line 547

def limit_value_with_default
  (limit_value || 30).to_i
end

#merge(other) ⇒ ElasticSearch::Relation

Creates a new relation while merging the attributes (constraints, settings, etc) of the current relation with the attributes of another one passed as argument. For multi-value contstraints the resulting relation will include constraints of both relations. For single-value constraints, the values of the relation 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:



37
38
39
40
41
42
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
68
# File 'lib/elastic_search/relation.rb', line 37

def merge(other)
  other = other.relation

  fresh.tap do |relation|
    relation.profile_value = other.profile_value if other.profile_value != nil
    relation.source_value = (relation.source_value || []) + other.source_value if other.source_value
    relation.sort_values = (relation.sort_values || []) + other.sort_values if other.sort_values
    relation.highlight_values = (relation.highlight_values || {}).merge(other.highlight_values) if other.highlight_values
    relation.suggest_values = (relation.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
    relation.offset_value = other.offset_value if other.offset_value
    relation.limit_value = other.limit_value if other.limit_value
    relation.includes_values = (relation.includes_values || []) + other.includes_values if other.includes_values
    relation.preload_values = (relation.preload_values || []) + other.preload_values if other.preload_values
    relation.eager_load_values = (relation.eager_load_values || []) + other.eager_load_values if other.eager_load_values
    relation.failsafe_value = other.failsafe_value if other.failsafe_value != nil
    relation.scroll_args = other.scroll_args if other.scroll_args
    relation.custom_value = (relation.custom_value || {}).merge(other.custom_value) if other.custom_value
    relation.search_values = (relation.search_values || []) + other.search_values if other.search_values
    relation.must_values = (relation.must_values || []) + other.must_values if other.must_values
    relation.must_not_values = (relation.must_not_values || []) + other.must_not_values if other.must_not_values
    relation.should_values = (relation.should_values || []) + other.should_values if other.should_values
    relation.filter_values = (relation.filter_values || []) + other.filter_values if other.filter_values
    relation.post_search_values = (relation.post_search_values || []) + other.post_search_values if other.post_search_values
    relation.post_must_values = (relation.post_must_values || []) + other.post_must_values if other.post_must_values
    relation.post_must_not_values = (relation.post_must_not_values || []) + other.post_must_not_values if other.post_must_not_values
    relation.post_should_values = (relation.post_should_values || []) + other.post_should_values if other.post_should_values
    relation.post_filter_values = (relation.post_filter_vales || []) + other.post_filter_values if other.post_filter_values
    relation.aggregation_values = (relation.aggregation_values || {}).merge(other.aggregation_values) if other.aggregation_values
    relation.terminate_after_value = other.terminate_after_value if other.terminate_after_value != nil
    relation.timeout_value = other.timeout_value if other.timeout_value != nil
  end
end

#offset(n) ⇒ ElasticSearch::Relation

Sets the request offset, ie ElasticSearch's from parameter that is used to skip results in the result set from being returned.

Examples:

CommentIndex.offset(100)

Parameters:

  • n (Fixnum)

    The offset value, ie the number of results that are skipped in the result set

Returns:



512
513
514
515
516
# File 'lib/elastic_search/relation.rb', line 512

def offset(n)
  fresh.tap do |relation|
    relation.offset_value = n.to_i
  end
end

#offset_value_with_defaultFixnum

Returns the offset value or, if not yet set, the default limit value (0).

Returns:

  • (Fixnum)

    The offset value



522
523
524
# File 'lib/elastic_search/relation.rb', line 522

def offset_value_with_default
  (offset_value || 0).to_i
end

#page(n) ⇒ Object



570
571
572
# File 'lib/elastic_search/relation.rb', line 570

def page(n)
  paginate(page: n)
end

#paginate(page:, per_page: limit_value_with_default) ⇒ ElasticSearch::Relation

Sets pagination parameters for the relation by using offset and limit, ie ElasticSearch's from and size parameters.

Examples:

CommentIndex.paginate(page: 3)
CommentIndex.paginate(page: 5, per_page: 60)

Parameters:

  • page (#to_i)

    The current page

  • per_page (#to_i)

    The number of results per page

Returns:



563
564
565
566
567
568
# File 'lib/elastic_search/relation.rb', line 563

def paginate(page:, per_page: limit_value_with_default)
  page = [page.to_i, 1].max
  per_page = per_page.to_i

  offset((page - 1) * per_page).limit(per_page)
end

#per(n) ⇒ Object



574
575
576
# File 'lib/elastic_search/relation.rb', line 574

def per(n)
  paginate(page: offset_value_with_default / limit_value_with_default + 1, per_page: n)
end

#preload(*args) ⇒ ElasticSearch::Relation

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:



416
417
418
419
420
# File 'lib/elastic_search/relation.rb', line 416

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

#profile(value) ⇒ ElasticSearch::Relation

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:



289
290
291
292
293
# File 'lib/elastic_search/relation.rb', line 289

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

#relationElasticSearch::Relation

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:



134
135
136
# File 'lib/elastic_search/relation.rb', line 134

def relation
  self
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



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/elastic_search/relation.rb', line 154

def request
  res = {}

  if must_values || search_values || must_not_values || should_values || filter_values
    if ElasticSearch.version.to_i >= 2
      res[:query] = {
        bool: {}.
          merge(must_values || search_values ? { must: (must_values || []) + (search_values || [])} : {}).
          merge(must_not_values ? { must_not: must_not_values } : {}).
          merge(should_values ? { should: should_values } : {}).
          merge(filter_values ? { filter: filter_values } : {})
      }
    else
      filters = (filter_values || []) + (must_not_values || []).map { |must_not_value| { not: must_not_value } }

      queries = {}.
        merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {}).
        merge(should_values ? { should: should_values } : {})

      if filters.size > 0
        res[:query] = {
          filtered: {}.
            merge(queries.size > 0 ? { query: { bool: queries } } : {}).
            merge(filter: filters.size > 1 ? { and: filters } : filters.first)
        }
      else
        res[:query] = { bool: queries }
      end
    end
  end

  res.update from: offset_value_with_default, size: limit_value_with_default

  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_search_values || post_must_not_values || post_should_values || post_filter_values
    if ElasticSearch.version.to_i >= 2
      res[:post_filter] = {
        bool: {}.
          merge(post_must_values || post_search_values ? { must: (post_must_values || []) + (post_search_values || []) } : {}).
          merge(post_must_not_values ? { must_not: post_must_not_values } : {}).
          merge(post_should_values ? { should: post_should_values } : {}).
          merge(post_filter_values ? { filter: post_filter_values } : {})
      }
    else
      post_filters = (post_filter_values || []) + (post_must_not_values || []).map { |post_must_not_value| { not: post_must_not_value } }

      post_queries = {}.
        merge(post_must_values || post_search_values ? { must: (post_must_values || []) + (post_search_values || []) } : {}).
        merge(post_should_values ? { should: post_should_values } : {})

      post_filters_and_queries = post_filters + (post_queries.size > 0 ? [bool: post_queries] : [])

      res[:post_filter] = post_filters_and_queries.size > 1 ? { and: post_filters_and_queries } : post_filters_and_queries.first
    end
  end

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

  res.update(custom_value) if custom_value

  res
end

#resort(*args) ⇒ ElasticSearch::Relation Also known as: reorder

Specify the sort order you want ElasticSearch to use for sorting the results with already existing sort orders being removed.

Examples:

CommentIndex.sort(user_id: "asc").resort(id: "desc")

# Same as

CommentIndex.sort(id: "desc")

Returns:

See Also:



471
472
473
474
475
# File 'lib/elastic_search/relation.rb', line 471

def resort(*args)
  fresh.tap do |relation|
    relation.sort_values = args
  end
end

#respond_to?(name, *args) ⇒ Boolean

Returns:

  • (Boolean)


721
722
723
# File 'lib/elastic_search/relation.rb', line 721

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

#scroll(id: nil, timeout: "1m") ⇒ ElasticSearch::Relation

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)

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

  • timeout (String)

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

Returns:



315
316
317
318
319
# File 'lib/elastic_search/relation.rb', line 315

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

#sort(*args) ⇒ ElasticSearch::Relation Also known as: order

Specify the sort order you want ElasticSearch to use for sorting the results. When you call this multiple times, the sort orders are appended to the already existing ones. The sort arguments get passed to ElasticSearch without modifications, such that you can use sort by script, etc here as well.

Examples:

Default usage

CommentIndex.sort(:user_id, :id)

# Same as

CommentIndex.sort(:user_id).sort(:id)

Default hash usage

CommentIndex.sort(user_id: "asc").sort(id: "desc")

# Same as

CommentIndex.sort({ user_id: "asc" }, { id: "desc" })

Sort by native script

CommentIndex.sort("_script" => "sort_script", lang: "native", order: "asc", type: "number")

Parameters:

  • args

    The sort values that get passed to ElasticSearch

Returns:



449
450
451
452
453
# File 'lib/elastic_search/relation.rb', line 449

def sort(*args)
  fresh.tap do |relation|
    relation.sort_values = (sort_values || []) + args
  end
end

#source(value) ⇒ ElasticSearch::Relation

Use to specify which fields of the source document you want ElasticSearch to return for each matching result.

Examples:

CommentIndex.source([:id, :message]).search("hello world")

Parameters:

  • value (Array)

    Array listing the field names of the source document

Returns:



359
360
361
362
363
# File 'lib/elastic_search/relation.rb', line 359

def source(value)
  fresh.tap do |relation|
    relation.source_value = value
  end
end

#suggest(name, options = {}) ⇒ ElasticSearch::Relation

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:



273
274
275
276
277
# File 'lib/elastic_search/relation.rb', line 273

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

#terminate_after(n) ⇒ ElasticSearch::Relation

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")

Returns:



93
94
95
96
97
# File 'lib/elastic_search/relation.rb', line 93

def terminate_after(n)
  fresh.tap do |relation|
    relation.terminate_after_value = n
  end
end

#timeout(n) ⇒ ElasticSearch::Relation

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")

Returns:



79
80
81
82
83
# File 'lib/elastic_search/relation.rb', line 79

def timeout(n)
  fresh.tap do |relation|
    relation.timeout_value = n
  end
end

#unscope(*scopes) ⇒ ElasticSearch::Relation

Creates a new relation while removing all specified scopes. Currently, you can unscope :search, :post_search, :sort, :highlight, :suggest, :custom and :aggregate.

Examples:

CommentIndex.search("hello world").aggregate(:username).unscope(:search, :aggregate)

Parameters:

  • scopes (Symbol)

    All scopes that you want to remove

Returns:

Raises:

  • (ArgumentError)


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/elastic_search/relation.rb', line 110

def unscope(*scopes)
  unknown = scopes - [:search, :post_search, :sort, :highlight, :suggest, :custom, :aggregate]

  raise(ArgumentError, "Can't unscope #{unknown.join(", ")}") if unknown.size > 0

  scopes = scopes.to_set

  fresh.tap do |relation|
    relation.search_values = nil if scopes.include?(:search)
    relation.post_search_values = nil if scopes.include?(:search)
    relation.sort_values = nil if scopes.include?(:sort)
    relation.hightlight_values = nil if scopes.include?(:highlight)
    relation.suggest_values = nil if scopes.include?(:suggest)
    relation.custom_values = nil if scopes.include?(:custom)
    relation.aggregation_values = nil if scopes.include?(:aggregate)
  end
end