Class: Chewy::Query

Inherits:
Object show all
Includes:
Loading, Pagination, Search::Scoping, Enumerable
Defined in:
lib/chewy/query.rb,
lib/chewy/query/compose.rb,
lib/chewy/query/filters.rb,
lib/chewy/query/loading.rb,
lib/chewy/query/criteria.rb,
lib/chewy/query/nodes/or.rb,
lib/chewy/query/nodes/and.rb,
lib/chewy/query/nodes/not.rb,
lib/chewy/query/nodes/raw.rb,
lib/chewy/query/nodes/base.rb,
lib/chewy/query/nodes/bool.rb,
lib/chewy/query/nodes/expr.rb,
lib/chewy/query/pagination.rb,
lib/chewy/query/nodes/equal.rb,
lib/chewy/query/nodes/field.rb,
lib/chewy/query/nodes/query.rb,
lib/chewy/query/nodes/range.rb,
lib/chewy/query/nodes/exists.rb,
lib/chewy/query/nodes/prefix.rb,
lib/chewy/query/nodes/regexp.rb,
lib/chewy/query/nodes/script.rb,
lib/chewy/query/nodes/missing.rb,
lib/chewy/query/nodes/has_child.rb,
lib/chewy/query/nodes/match_all.rb,
lib/chewy/query/nodes/has_parent.rb,
lib/chewy/query/nodes/has_relation.rb

Overview

Query allows you to create ES search requests with convenient chainable DSL. Queries are lazy evaluated and might be merged. The same DSL is used for whole index or individual types query build.

Examples:

UsersIndex.filter{ age < 42 }.query(text: {name: 'Alex'}).limit(20)
UsersIndex::User.filter{ age < 42 }.query(text: {name: 'Alex'}).limit(20)

Defined Under Namespace

Modules: Compose, Loading, Nodes, Pagination Classes: Criteria, Filters

Constant Summary collapse

DELEGATED_METHODS =
%i[
  explain query_mode filter_mode post_filter_mode
  timeout limit offset highlight min_score rescore facets script_score
  boost_factor weight random_score field_value_factor decay aggregations
  suggest none strategy query filter post_filter boost_mode
  score_mode order reorder only types delete_all find total
  total_count total_entries unlimited script_fields track_scores preference
].to_set.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Search::Scoping

#scoping

Methods included from Pagination

#total

Methods included from Loading

#load, #preload

Constructor Details

#initialize(*indexes_or_types_and_options) ⇒ Query

Returns a new instance of Query.



35
36
37
38
39
40
41
# File 'lib/chewy/query.rb', line 35

def initialize(*indexes_or_types_and_options)
  @options = indexes_or_types_and_options.extract_options!
  @_types = indexes_or_types_and_options.select { |klass| klass < Chewy::Type }
  @_indexes = indexes_or_types_and_options.select { |klass| klass < Chewy::Index }
  @_indexes |= @_types.map(&:index)
  @criteria = Criteria.new
end

Instance Attribute Details

#_indexesObject (readonly)

Returns the value of attribute _indexes.



33
34
35
# File 'lib/chewy/query.rb', line 33

def _indexes
  @_indexes
end

#_typesObject (readonly)

Returns the value of attribute _types.



33
34
35
# File 'lib/chewy/query.rb', line 33

def _types
  @_types
end

#criteriaObject (readonly)

Returns the value of attribute criteria.



33
34
35
# File 'lib/chewy/query.rb', line 33

def criteria
  @criteria
end

#optionsObject (readonly)

Returns the value of attribute options.



33
34
35
# File 'lib/chewy/query.rb', line 33

def options
  @options
end

Instance Method Details

#==(other) ⇒ Object

Comparation with other query or collection If other is collection - search request is executed and result is used for comparation

Examples:

UsersIndex.filter(term: {name: 'Johny'}) == UsersIndex.filter(term: {name: 'Johny'}) # => true
UsersIndex.filter(term: {name: 'Johny'}) == UsersIndex.filter(term: {name: 'Johny'}).to_a # => true
UsersIndex.filter(term: {name: 'Johny'}) == UsersIndex.filter(term: {name: 'Winnie'}) # => false


57
58
59
# File 'lib/chewy/query.rb', line 57

def ==(other)
  super || other.is_a?(self.class) ? other.criteria == criteria : other == to_a
end

#_build_fqn_aggsObject



594
595
596
597
598
599
600
601
602
603
604
605
606
# File 'lib/chewy/query.rb', line 594

def _build_fqn_aggs
  named_aggs = {}
  @_indexes.each do |index|
    named_aggs[index.to_s.downcase] ||= {}
    index.types.each do |type|
      named_aggs[index.to_s.downcase][type.to_s.downcase] ||= {}
      type._agg_defs.each do |agg_name, prc|
        named_aggs[index.to_s.downcase][type.to_s.downcase][agg_name.to_s.downcase] = prc.call
      end
    end
  end
  named_aggs
end

#_build_named_aggsObject

In this simplest of implementations each named aggregation must be uniquely named



582
583
584
585
586
587
588
589
590
591
592
# File 'lib/chewy/query.rb', line 582

def _build_named_aggs
  named_aggs = {}
  @_indexes.each do |index|
    index.types.each do |type|
      type._agg_defs.each do |agg_name, prc|
        named_aggs[agg_name] = prc.call
      end
    end
  end
  named_aggs
end

#_get_fully_qualified_named_agg(str) ⇒ Object



608
609
610
611
612
613
614
# File 'lib/chewy/query.rb', line 608

def _get_fully_qualified_named_agg(str)
  parts = str.scan(/\A(\S+)#(\S+)\.(\S+)\z/).first
  idx = "#{parts[0]}index"
  type = "#{idx}::#{parts[1]}"
  agg_name = parts[2]
  @_fully_qualified_named_aggs[idx][type][agg_name]
end

#aggregations(params = nil) ⇒ Object Also known as: aggs

Sets elasticsearch aggregations search request param

Examples:

UsersIndex.filter{ name == 'Johny' }.aggregations(category_id: {terms: {field: 'category_ids'}})
   # => {body: {
          query: {...},
          aggregations: {
            terms: {
              field: 'category_ids'
            }
          }
        }}


568
569
570
571
572
573
574
575
576
577
578
# File 'lib/chewy/query.rb', line 568

def aggregations(params = nil)
  @_named_aggs ||= _build_named_aggs
  @_fully_qualified_named_aggs ||= _build_fqn_aggs
  if params
    params = {params => @_named_aggs[params]} if params.is_a?(Symbol)
    params = {params => _get_fully_qualified_named_agg(params)} if params.is_a?(String) && params =~ /\A\S+#\S+\.\S+\z/
    chain { criteria.update_aggregations params }
  else
    _response['aggregations'] || {}
  end
end

#boost_factor(factor, options = {}) ⇒ Object

Adds a boost factor to the search request. All scores are added to the search request and combinded according to boost_mode and score_mode

This probably only makes sense if you specify a filter for the boost factor as well

Examples:

UsersIndex.boost_factor(23, filter: { term: { foo: :bar} })
    # => {body:
           query: {
             function_score: {
               query: { ...},
               functions: [{
                 boost_factor: 23,
                 filter: { term: { foo: :bar } }
               }]
             } } }


420
421
422
423
# File 'lib/chewy/query.rb', line 420

def boost_factor(factor, options = {})
  scoring = options.merge(boost_factor: factor.to_i)
  chain { criteria.update_scores scoring }
end

#boost_mode(value) ⇒ Object

Sets the boost mode for custom scoring/boosting. Not used if no score functions are specified Possible values:

  • :multiply Default value. Query score and function result are multiplied.

  • :replace Only function result is used, query score is ignored.

  • :sum Query score and function score are added.

  • :avg Average of query and function score.

  • :max Max of query and function score.

  • :min Min of query and function score.

Default value for :boost_mode might be changed with Chewy.score_mode config option.

Examples:

UsersIndex.boost_mode('multiply').script_score('doc['boost'].value')
  # => {body: {query: function_score: {
    query: {...},
    boost_mode: 'multiply',
    functions: [ ... ]
  }}}


797
798
799
# File 'lib/chewy/query.rb', line 797

def boost_mode(value)
  chain { criteria.update_options boost_mode: value }
end

#decay(function, field, options = {}) ⇒ Object

Add a decay scoring to the search. All scores are added to the search request and combinded according to boost_mode and score_mode

The parameters have default values, but those may not be very useful for most applications.

Examples:

UsersIndex.decay(
             :gauss,
             :field,
             origin: '11, 12',
             scale: '2km',
             offset: '5km',
             decay: 0.4,
             filter: { foo: :bar})
    # => {body:
           query: {
             gauss: {
               query: { ...},
               functions: [{
                 gauss: {
                   field: {
                     origin: '11, 12',
                     scale: '2km',
                     offset: '5km',
                     decay: 0.4
                   }
                 },
                 filter: { foo: :bar }
               }]
             } } }


537
538
539
540
541
542
543
# File 'lib/chewy/query.rb', line 537

def decay(function, field, options = {})
  field_options = options.extract!(:origin, :scale, :offset, :decay).delete_if { |_, v| v.nil? }
  scoring = options.merge(function => {
    field => field_options
  })
  chain { criteria.update_scores scoring }
end

#delete_allObject

Deletes all documents matching a query.

Examples:

UsersIndex.delete_all
UsersIndex.filter{ age <= 42 }.delete_all
UsersIndex::User.delete_all
UsersIndex::User.filter{ age <= 42 }.delete_all


980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
# File 'lib/chewy/query.rb', line 980

def delete_all
  if Runtime.version >= '2.0'
    plugins = Chewy.client.nodes.info(plugins: true)['nodes'].values.map { |item| item['plugins'] }.flatten
    raise PluginMissing, 'install delete-by-query plugin' unless plugins.find { |item| item['name'] == 'delete-by-query' }
  end

  request = chain { criteria.update_options simple: true }.send(:_request)

  ActiveSupport::Notifications.instrument 'delete_query.chewy',
    request: request, indexes: _indexes, types: _types,
    index: _indexes.one? ? _indexes.first : _indexes,
    type: _types.one? ? _types.first : _types do
      if Runtime.version >= '2.0'
        path = Elasticsearch::API::Utils.__pathify(
          Elasticsearch::API::Utils.__listify(request[:index]),
          Elasticsearch::API::Utils.__listify(request[:type]),
          '/_query'
        )
        Chewy.client.perform_request(Elasticsearch::API::HTTP_DELETE, path, {}, request[:body]).body
      else
        Chewy.client.delete_by_query(request)
      end
    end
end

#exists?Boolean

Returns true if there are at least one document that matches the query

Examples:

PlacesIndex.query(...).filter(...).exists?

Returns:

  • (Boolean)


1033
1034
1035
# File 'lib/chewy/query.rb', line 1033

def exists?
  search_type(:count).total > 0
end

#explain(value = nil) ⇒ Object

Adds explain parameter to search request.

Calling explain without any arguments sets explanation flag to true. With explain: true, every result object has _explanation method

Examples:

UsersIndex.filter(term: {name: 'Johny'}).explain
UsersIndex.filter(term: {name: 'Johny'}).explain(true)
UsersIndex.filter(term: {name: 'Johny'}).explain(false)
UsersIndex::User.filter(term: {name: 'Johny'}).explain.first._explanation # => {...}


75
76
77
# File 'lib/chewy/query.rb', line 75

def explain(value = nil)
  chain { criteria.update_request_options explain: (value.nil? ? true : value) }
end

#facets(params = nil) ⇒ Object

Adds facets section to the search request. All the chained facets a merged and added to the search request

If called parameterless - returns result facets from ES performing request. Returns empty hash if no facets was requested or resulted.

Examples:

UsersIndex.facets(tags: {terms: {field: 'tags'}}).facets(ages: {terms: {field: 'age'}})
  # => {body: {
         query: {...},
         facets: {tags: {terms: {field: 'tags'}}, ages: {terms: {field: 'age'}}}
       }}

Raises:



370
371
372
373
374
375
376
377
# File 'lib/chewy/query.rb', line 370

def facets(params = nil)
  raise RemovedFeature, 'removed in elasticsearch 2.0' if Runtime.version >= '2.0'
  if params
    chain { criteria.update_facets params }
  else
    _response['facets'] || {}
  end
end

#field_value_factor(settings, options = {}) ⇒ Object

Add a field value scoring to the search. All scores are added to the search request and combinded according to boost_mode and score_mode

This function is only available in Elasticsearch 1.2 and greater

Examples:

UsersIndex.field_value_factor(
             {
               field: :boost,
               factor: 1.2,
               modifier: :sqrt
             }, filter: { foo: :bar})
    # => {body:
           query: {
             function_score: {
               query: { ...},
               functions: [{
                 field_value_factor: {
                   field: :boost,
                   factor: 1.2,
                   modifier: :sqrt
                 },
                 filter: { foo: :bar }
               }]
             } } }


500
501
502
503
# File 'lib/chewy/query.rb', line 500

def field_value_factor(settings, options = {})
  scoring = options.merge(field_value_factor: settings)
  chain { criteria.update_scores scoring }
end

#filter(params = nil, &block) ⇒ Object

Adds one or more filter to the search request Internally filters are stored as an array While the full query compilation this array compiles according to :filter_mode option value

By default it joins inside and filter See #filter_mode chainable method for more info.

Also this method supports block DSL. See Chewy::Query::Filters for more info.

If only one filter was specified, it will become a result filter as is, without joining.

Examples:

UsersIndex.filter(term: {name: 'Johny'}).filter(range: {age: {lte: 42}})
UsersIndex::User.filter(term: {name: 'Johny'}).filter(range: {age: {lte: 42}})
UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }
  # => {body: {query: {filtered: {
         query: {...},
         filter: {and: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}
       }}}}
UsersIndex.filter(term: {name: 'Johny'})
  # => {body: {query: {filtered: {
         query: {...},
         filter: {term: {name: 'Johny'}}
       }}}}


727
728
729
730
# File 'lib/chewy/query.rb', line 727

def filter(params = nil, &block)
  params = Filters.new(&block).__render__ if block
  chain { criteria.update_filters params }
end

#filter_mode(value) ⇒ Object

Sets query compilation mode for search request. Not used if only one filter for search is specified. Possible values:

  • :and Default value. Filter compiles into an and filter.

  • :or Filter compiles into an or filter.

  • :must Filter compiles into a bool must filter.

  • :should Filter compiles into a bool should filter.

  • Any acceptable minimum_should_match value (1, '2', '75%') Filter compiles into bool should filter with minimum_should_match set.

Default value for :filter_mode might be changed with Chewy.filter_mode config option.

Examples:

UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }
  # => {body: {query: {filtered: {
         query: {...},
         filter: {and: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}
       }}}}
UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }.filter_mode(:or)
  # => {body: {query: {filtered: {
         query: {...},
         filter: {or: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}
       }}}}
UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }.filter_mode(:must)
  # => {body: {query: {filtered: {
         query: {...},
         filter: {bool: {must: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}}}
UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }.filter_mode(:should)
  # => {body: {query: {filtered: {
         query: {...},
         filter: {bool: {should: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}}}
UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }.filter_mode('50%')
  # => {body: {query: {filtered: {
         query: {...},
         filter: {bool: {
           should: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}],
           minimum_should_match: '50%'
         }}
       }}}}
Chewy.filter_mode = :should
Chewy.filter_mode = '50%'


225
226
227
# File 'lib/chewy/query.rb', line 225

def filter_mode(value)
  chain { criteria.update_options filter_mode: value }
end

#find(*ids) ⇒ Object

Find all documents matching a query.

In all the previous examples find will return a single object. To get a collection - pass an array of ids.

Examples:

UsersIndex.find(42)
UsersIndex.filter{ age <= 42 }.find(42)
UsersIndex::User.find(42)
UsersIndex::User.filter{ age <= 42 }.find(42)
UsersIndex::User.find(42, 7, 3) # array of objects with ids in [42, 7, 3]
UsersIndex::User.find([8, 13])  # array of objects with ids in [8, 13]
UsersIndex::User.find([42])     # array of the object with id == 42

Raises:



1021
1022
1023
1024
1025
1026
# File 'lib/chewy/query.rb', line 1021

def find(*ids)
  results = chain { criteria.update_options simple: true }.filter { _id == ids.flatten }.to_a

  raise Chewy::DocumentNotFound, "Could not find documents for ids #{ids.flatten}" if results.empty?
  ids.one? && !ids.first.is_a?(Array) ? results.first : results
end

#highlight(value) ⇒ Object

Elasticsearch highlight query option support

Examples:

UsersIndex.query(...).highlight(fields: { ... })


325
326
327
# File 'lib/chewy/query.rb', line 325

def highlight(value)
  chain { criteria.update_request_options highlight: value }
end

#limit(value = nil, &block) ⇒ Object

Sets elasticsearch size search request param Default value is set in the elasticsearch and is 10.

Examples:

UsersIndex.filter{ name == 'Johny' }.limit(100)
   # => {body: {
          query: {...},
          size: 100
        }}


303
304
305
# File 'lib/chewy/query.rb', line 303

def limit(value = nil, &block)
  chain { criteria.update_request_options size: block || Integer(value) }
end

#merge(other) ⇒ Object

Merges two queries. Merges all the values in criteria with the same rules as values added manually.

Examples:

scope1 = UsersIndex.filter{ name == 'Johny' }
scope2 = UsersIndex.filter{ age <= 42 }
scope3 = UsersIndex.filter{ name == 'Johny' }.filter{ age <= 42 }

scope1.merge(scope2) == scope3 # => true


968
969
970
# File 'lib/chewy/query.rb', line 968

def merge(other)
  chain { criteria.merge!(other.criteria) }
end

#min_score(value) ⇒ Object

Elasticsearch minscore option support

Examples:

UsersIndex.query(...).min_score(0.5)


343
344
345
# File 'lib/chewy/query.rb', line 343

def min_score(value)
  chain { criteria.update_request_options min_score: value }
end

#noneObject

Marks the criteria as having zero documents. This scope always returns empty array without touching the elasticsearch server. All the chained calls of methods don't affect the result

Examples:

UsersIndex.none.to_a
  # => []
UsersIndex.query(text: {name: 'Johny'}).none.to_a
  # => []
UsersIndex.none.query(text: {name: 'Johny'}).to_a
  # => []


650
651
652
# File 'lib/chewy/query.rb', line 650

def none
  chain { criteria.update_options none: true }
end

#offset(value = nil, &block) ⇒ Object

Sets elasticsearch from search request param

Examples:

UsersIndex.filter{ name == 'Johny' }.offset(300)
   # => {body: {
          query: {...},
          from: 300
        }}


316
317
318
# File 'lib/chewy/query.rb', line 316

def offset(value = nil, &block)
  chain { criteria.update_request_options from: block || Integer(value) }
end

#only(*params) ⇒ Object

Sets search request field list

Examples:

UsersIndex.only(:first_name, :last_name).only(:age)
  # => {body: {
         query: {...},
         fields: ['first_name', 'last_name', 'age']
       }}


876
877
878
# File 'lib/chewy/query.rb', line 876

def only(*params)
  chain { criteria.update_fields params }
end

#only!(*params) ⇒ Object

Cleans up previous search field list and sets the new one

Examples:

UsersIndex.only(:first_name, :last_name).only!(:age)
  # => {body: {
         query: {...},
         fields: ['age']
       }}


889
890
891
# File 'lib/chewy/query.rb', line 889

def only!(*params)
  chain { criteria.update_fields params, purge: true }
end

#order(*params) ⇒ Object

Sets search request sorting

Examples:

UsersIndex.order(:first_name, :last_name).order(age: :desc).order(price: {order: :asc, mode: :avg})
  # => {body: {
         query: {...},
         sort: ['first_name', 'last_name', {age: 'desc'}, {price: {order: 'asc', mode: 'avg'}}]
       }}


850
851
852
# File 'lib/chewy/query.rb', line 850

def order(*params)
  chain { criteria.update_sort params }
end

#post_filter(params = nil, &block) ⇒ Object

Adds one or more post_filter to the search request Internally post_filters are stored as an array While the full query compilation this array compiles according to :post_filter_mode option value

By default it joins inside and filter See #post_filter_mode chainable method for more info.

Also this method supports block DSL. See Chewy::Query::Filters for more info.

If only one post_filter was specified, it will become a result post_filter as is, without joining.

Examples:

UsersIndex.post_filter(term: {name: 'Johny'}).post_filter(range: {age: {lte: 42}})
UsersIndex::User.post_filter(term: {name: 'Johny'}).post_filter(range: {age: {lte: 42}})
UsersIndex.post_filter{ name == 'Johny' }.post_filter{ age <= 42 }
  # => {body: {
         post_filter: {and: [{term: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}
       }}
UsersIndex.post_filter(term: {name: 'Johny'})
  # => {body: {
         post_filter: {term: {name: 'Johny'}}
       }}


760
761
762
763
# File 'lib/chewy/query.rb', line 760

def post_filter(params = nil, &block)
  params = Filters.new(&block).__render__ if block
  chain { criteria.update_post_filters params }
end

#post_filter_mode(value) ⇒ Object

Acts the same way as filter_mode, but used for post_filter. Note that it fallbacks by default to Chewy.filter_mode if Chewy.post_filter_mode is nil.

Examples:

UsersIndex.post_filter{ name == 'Johny' }.post_filter{ age <= 42 }.post_filter_mode(:and)
UsersIndex.post_filter{ name == 'Johny' }.post_filter{ age <= 42 }.post_filter_mode(:should)
UsersIndex.post_filter{ name == 'Johny' }.post_filter{ age <= 42 }.post_filter_mode('50%')


238
239
240
# File 'lib/chewy/query.rb', line 238

def post_filter_mode(value)
  chain { criteria.update_options post_filter_mode: value }
end

#preference(value) ⇒ Object

Sets preference for request. For instance, one can use preference=_primary to execute only on the primary shards.

Examples:

scope = UsersIndex.preference(:_primary)


551
552
553
# File 'lib/chewy/query.rb', line 551

def preference(value)
  chain { criteria.update_search_options preference: value }
end

#query(params) ⇒ Object

Adds one or more query to the search request Internally queries are stored as an array While the full query compilation this array compiles according to :query_mode option value

By default it joines inside must query See #query_mode chainable method for more info.

If only one query was specified, it will become a result query as is, without joining.

Examples:

UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}})
UsersIndex::User.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}})
  # => {body: {
         query: {bool: {must: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}
UsersIndex.query(text: {name: 'Johny'})
  # => {body: {
         query: {text: {name: 'Johny'}}
       }}


693
694
695
# File 'lib/chewy/query.rb', line 693

def query(params)
  chain { criteria.update_queries params }
end

#query_mode(value) ⇒ Object

Sets query compilation mode for search request. Not used if only one filter for search is specified. Possible values:

  • :must Default value. Query compiles into a bool must query.

  • :should Query compiles into a bool should query.

  • Any acceptable minimum_should_match value (1, '2', '75%') Query compiles into a bool should query with minimum_should_match set.

  • :dis_max Query compiles into a dis_max query.

  • Any Float value (0.0, 0.7, 1.0) Query compiles into a dis_max query with tie_breaker option set.

Default value for :query_mode might be changed with Chewy.query_mode config option.

Examples:

UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}})
  # => {body: {
         query: {bool: {must: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}
UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}}).query_mode(:should)
  # => {body: {
         query: {bool: {should: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}
UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}}).query_mode('50%')
  # => {body: {
         query: {bool: {
           should: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}],
           minimum_should_match: '50%'
         }}
       }}
UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}}).query_mode(:dis_max)
  # => {body: {
         query: {dis_max: {queries: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}]}}
       }}
UsersIndex.query(text: {name: 'Johny'}).query(range: {age: {lte: 42}}).query_mode(0.7)
  # => {body: {
         query: {dis_max: {
           queries: [{text: {name: 'Johny'}}, {range: {age: {lte: 42}}}],
           tie_breaker: 0.7
         }}
       }}
Chewy.query_mode = :dis_max
Chewy.query_mode = '50%'


157
158
159
# File 'lib/chewy/query.rb', line 157

def query_mode(value)
  chain { criteria.update_options query_mode: value }
end

#random_score(seed = Time.now, options = {}) ⇒ Object

Adds a random score to the search request. All scores are added to the search request and combinded according to boost_mode and score_mode

This probably only makes sense if you specify a filter for the random score as well.

If you do not pass in a seed value, Time.now will be used

Examples:

UsersIndex.random_score(23, filter: { foo: :bar})
    # => {body:
           query: {
             function_score: {
               query: { ...},
               functions: [{
                 random_score: { seed: 23 },
                 filter: { foo: :bar }
               }]
             } } }


468
469
470
471
# File 'lib/chewy/query.rb', line 468

def random_score(seed = Time.now, options = {})
  scoring = options.merge(random_score: {seed: seed.to_i})
  chain { criteria.update_scores scoring }
end

#renderObject

A compatibility layer with the new request DSL.



44
45
46
# File 'lib/chewy/query.rb', line 44

def render
  _request
end

#reorder(*params) ⇒ Object

Cleans up previous search sorting and sets the new one

Examples:

UsersIndex.order(:first_name, :last_name).order(age: :desc).reorder(price: {order: :asc, mode: :avg})
  # => {body: {
         query: {...},
         sort: [{price: {order: 'asc', mode: 'avg'}}]
       }}


863
864
865
# File 'lib/chewy/query.rb', line 863

def reorder(*params)
  chain { criteria.update_sort params, purge: true }
end

#rescore(value) ⇒ Object

Elasticsearch rescore query option support

Examples:

UsersIndex.query(...).rescore(query: { ... })


334
335
336
# File 'lib/chewy/query.rb', line 334

def rescore(value)
  chain { criteria.update_request_options rescore: value }
end

#score_mode(value) ⇒ Object

Sets the scoring mode for combining function scores/boosts Not used if no score functions are specified. Possible values:

  • :multiply Default value. Scores are multiplied.

  • :sum Scores are summed.

  • :avg Scores are averaged.

  • :first The first function that has a matching filter is applied.

  • :max Maximum score is used.

  • :min Minimum score is used

Default value for :score_mode might be changed with Chewy.score_mode config option.

Examples:

UsersIndex.score_mode('multiply').script_score('doc['boost'].value')
  # => {body: {query: function_score: {
    query: {...},
    score_mode: 'multiply',
    functions: [ ... ]
  }}}
Chewy.score_mode = :first


837
838
839
# File 'lib/chewy/query.rb', line 837

def score_mode(value)
  chain { criteria.update_options score_mode: value }
end

#script_fields(value) ⇒ Object

Adds script_fields parameter to search request.

Examples:

UsersIndex.script_fields(
  distance: {
    params: {
      lat: 37.569976,
      lon: -122.351591
    },
    script: "doc['coordinates'].distanceInMiles(lat, lon)"
  }
)


91
92
93
# File 'lib/chewy/query.rb', line 91

def script_fields(value)
  chain { criteria.update_script_fields(value) }
end

#script_score(script, options = {}) ⇒ Object

Adds a script function to score the search request. All scores are added to the search request and combinded according to boost_mode and score_mode

Examples:

UsersIndex.script_score("doc['boost'].value", params: { modifier: 2 })
    # => {body:
           query: {
             function_score: {
               query: { ...},
               functions: [{
                 script_score: {
                    script: "doc['boost'].value * modifier",
                    params: { modifier: 2 }
                  }
                 }
               }]
             } } }


397
398
399
400
# File 'lib/chewy/query.rb', line 397

def script_score(script, options = {})
  scoring = {script_score: {script: script}.merge(options)}
  chain { criteria.update_scores scoring }
end

#search_type(value) ⇒ Object

Sets search_type for request. For instance, one can use search_type=count to fetch only total count of documents or to fetch only aggregations without fetching documents.

Examples:

scope = UsersIndex.search_type(:count)
scope.count == 0  # no documents actually fetched
scope.total == 10 # but we know a total count of them

scope = UsersIndex.aggs(max_age: { max: { field: 'age' } }).search_type(:count)
max_age = scope.aggs['max_age']['value']


954
955
956
# File 'lib/chewy/query.rb', line 954

def search_type(value)
  chain { criteria.update_search_options search_type: value }
end

#strategy(value = nil) ⇒ Object

Setups strategy for top-level filtered query

Examples:

UsersIndex.filter { name == 'Johny'}.strategy(:leap_frog)
 # => {body: {
        query: { filtered: {
          filter: { term: { name: 'Johny' } },
          strategy: 'leap_frog'
        } }
      }}


665
666
667
# File 'lib/chewy/query.rb', line 665

def strategy(value = nil)
  chain { criteria.update_options strategy: value }
end

#suggest(params = nil) ⇒ Object

Sets elasticsearch suggest search request param

Examples:

UsersIndex.suggest(name: {text: 'Joh', term: {field: 'name'}})
   # => {body: {
          query: {...},
          suggest: {
            text: 'Joh',
            term: {
              field: 'name'
            }
          }
        }}


630
631
632
633
634
635
636
# File 'lib/chewy/query.rb', line 630

def suggest(params = nil)
  if params
    chain { criteria.update_suggest params }
  else
    _response['suggest'] || {}
  end
end

#timed_outObject

Returns request timed_out as reported by elasticsearch

The timed_out value tells us whether the query timed out or not.

By default, search requests do not timeout. If low response times are more important to you than complete results, you can specify a timeout as 10 or "10ms" (10 milliseconds), or "1s" (1 second). See #timeout method.

Examples:

UsersIndex.query(...).filter(...).timed_out


1068
1069
1070
# File 'lib/chewy/query.rb', line 1068

def timed_out
  _response['timed_out']
end

#timeout(value) ⇒ Object

A search timeout, bounding the search request to be executed within the specified time value and bail with the hits accumulated up to that point when expired. Defaults to no timeout.

By default, the coordinating node waits to receive a response from all shards. If one node is having trouble, it could slow down the response to all search requests.

The timeout parameter tells the coordinating node how long it should wait before giving up and just returning the results that it already has. It can be better to return some results than none at all.

The response to a search request will indicate whether the search timed out and how many shards responded successfully:

The primary shard assigned to perform the index operation might not be available when the index operation is executed. Some reasons for this might be that the primary shard is currently recovering from a gateway or undergoing relocation. By default, the index operation will wait on the primary shard to become available for up to 1 minute before failing and responding with an error. The timeout parameter can be used to explicitly specify how long it waits.

Timeout is not a circuit breaker.

It should be noted that this timeout does not halt the execution of the query, it merely tells the coordinating node to return the results collected so far and to close the connection. In the background, other shards may still be processing the query even though results have been sent.

Use the timeout because it is important to your SLA, not because you want to abort the execution of long running queries.

Examples:

...
"timed_out":     true,
"_shards": {
    "total":      5,
    "successful": 4,
    "failed":     1
},
...
UsersIndex.timeout("5000ms")


289
290
291
# File 'lib/chewy/query.rb', line 289

def timeout(value)
  chain { criteria.update_request_options timeout: value }
end

#tookObject

Returns request total time elapsed as reported by elasticsearch

Examples:

UsersIndex.query(...).filter(...).took


1053
1054
1055
# File 'lib/chewy/query.rb', line 1053

def took
  _response['took']
end

#track_scores(value) ⇒ Object

Elasticsearch track_scores option support

Examples:

UsersIndex.query(...).track_scores(true)


352
353
354
# File 'lib/chewy/query.rb', line 352

def track_scores(value)
  chain { criteria.update_request_options track_scores: value }
end

#types(*params) ⇒ Object

Specify types participating in the search result Works via types filter. Always merged with another filters with the and filter.

Examples:

UsersIndex.types(:admin, :manager).filters{ name == 'Johny' }.filters{ age <= 42 }
  # => {body: {query: {filtered: {
         query: {...},
         filter: {and: [
           {or: [
             {type: {value: 'admin'}},
             {type: {value: 'manager'}}
           ]},
           {term: {name: 'Johny'}},
           {range: {age: {lte: 42}}}
         ]}
       }}}}

UsersIndex.types(:admin, :manager).filters{ name == 'Johny' }.filters{ age <= 42 }.filter_mode(:or)
  # => {body: {query: {filtered: {
         query: {...},
         filter: {and: [
           {or: [
             {type: {value: 'admin'}},
             {type: {value: 'manager'}}
           ]},
           {or: [
             {term: {name: 'Johny'}},
             {range: {age: {lte: 42}}}
           ]}
         ]}
       }}}}


926
927
928
# File 'lib/chewy/query.rb', line 926

def types(*params)
  chain { criteria.update_types params }
end

#types!(*params) ⇒ Object

Acts the same way as types, but cleans up previously set types

Examples:

UsersIndex.types(:admin).types!(:manager)
  # => {body: {query: {filtered: {
         query: {...},
         filter: {type: {value: 'manager'}}
       }}}}


939
940
941
# File 'lib/chewy/query.rb', line 939

def types!(*params)
  chain { criteria.update_types params, purge: true }
end

#unlimitedObject

Sets limit to be equal to total documents count

Examples:

PlacesIndex.query(...).filter(...).unlimited


1043
1044
1045
1046
# File 'lib/chewy/query.rb', line 1043

def unlimited
  count_query = search_type(:count)
  offset(0).limit { count_query.total }
end

#weight(factor, options = {}) ⇒ Object

Add a weight scoring function to the search. All scores are added to the search request and combinded according to boost_mode and score_mode

This probably only makes sense if you specify a filter for the weight as well.

Examples:

UsersIndex.weight(23, filter: { term: { foo: :bar} })
    # => {body:
           query: {
             function_score: {
               query: { ...},
               functions: [{
                 weight: 23,
                 filter: { term: { foo: :bar } }
               }]
             } } }


443
444
445
446
# File 'lib/chewy/query.rb', line 443

def weight(factor, options = {})
  scoring = options.merge(weight: factor.to_i)
  chain { criteria.update_scores scoring }
end