Module: ElasticSearch::FilterableRelation

Included in:
AggregationRelation, Relation
Defined in:
lib/elastic_search/filterable_relation.rb

Overview

The ElasticSearch::FilterableRelation mixin provides chainable methods like #where, #exists, #range, etc to add search filters to a relation.

Examples:

CommentIndex.where(public: true)
CommentIndex.exists(:user_id)
CommentIndex.range(:created_at, gt: Date.today - 7)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object


12
13
14
15
16
# File 'lib/elastic_search/filterable_relation.rb', line 12

def self.included(base)
  base.class_eval do
    attr_accessor :search_values, :must_values, :must_not_values, :should_values, :filter_values
  end
end

Instance Method Details

#exists(field) ⇒ ElasticSearch::Relation

Adds an exists filter to the relation, which selects all documents for which the specified field has a non-null value.

Examples:

CommentIndex.exists(:notified_at)

Parameters:

  • field (Symbol, String)

    The field that should have a non-null value

Returns:


219
220
221
# File 'lib/elastic_search/filterable_relation.rb', line 219

def exists(field)
  filter exists: { field: field }
end

#exists_not(field) ⇒ ElasticSearch::Relation

Adds an exists not filter to the relation, which selects all documents for which the specified field's value is null.

Examples:

CommentIndex.exists_not(:notified_at)

Parameters:

  • field (Symbol, String)

    The field that should have a null value

Returns:


233
234
235
# File 'lib/elastic_search/filterable_relation.rb', line 233

def exists_not(field)
  must_not exists: { field: field }
end

#filter(*args) ⇒ ElasticSearch::Relation

Adds raw filter queries to the relation.

Examples:

CommentIndex.filter(term: { state: "new" })
CommentIndex.filter(range: { created_at: { gte: Time.parse("2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw filter query arguments

Returns:


108
109
110
111
112
# File 'lib/elastic_search/filterable_relation.rb', line 108

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

#match_all(options = {}) ⇒ ElasticSearch::Relation

Adds a match all filter/query to the relation, which simply matches all documents. This can be eg be used within filter aggregations or for filter chaining. Check out the ElasticSearch docs for further details.

Examples:

Basic usage

CommentIndex.match_all

Filter chaining

query = CommentIndex.match_all
query = query.where(public: true) unless current_user.admin?

Filter aggregation

query = CommentIndex.aggregate(filtered_tags: {}) do |aggregation|
  aggregation = aggregation.match_all
  aggregation = aggregation.where(user_id: current_user.id) if current_user
  aggregation = aggregation.aggregate(:tags)
end

query.aggregations(:filtered_tags).tags.buckets.each { ... }

Parameters:

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

    Options for the match_all filter, like eg boost

Returns:


205
206
207
# File 'lib/elastic_search/filterable_relation.rb', line 205

def match_all(options = {})
  filter match_all: options
end

#must(*args) ⇒ ElasticSearch::Relation

Adds raw must queries to the relation.

Examples:

CommentIndex.must(term: { state: "new" })
CommentIndex.must(range: { created_at: { gt: Time.parse("2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw must query arguments

Returns:


124
125
126
127
128
# File 'lib/elastic_search/filterable_relation.rb', line 124

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

#must_not(*args) ⇒ ElasticSearch::Relation

Adds raw must_not queries to the relation.

Examples:

CommentIndex.must_not(term: { state: "new" })
CommentIndex.must_not(range: { created_at: { gt: Time.parse"2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw must_not query arguments

Returns:


140
141
142
143
144
# File 'lib/elastic_search/filterable_relation.rb', line 140

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

#range(field, options = {}) ⇒ ElasticSearch::Relation

Adds a range filter to the relation without being forced to specify the left and right end of the range, such that you can eg simply specify lt, lte, gt and gte. For fully specified ranges, you can as well use #where, etc. Check out the ElasticSearch docs for further details regarding the range filter.

Examples:

CommentIndex.range(:created_at, gte: Time.parse("2016-01-01"))
CommentIndex.range(:likes_count, gt: 10, lt: 100)

Parameters:

  • field (Symbol, String)

    The field name to specify the range for

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

    The range filter specification, like lt, lte, etc

Returns:


177
178
179
# File 'lib/elastic_search/filterable_relation.rb', line 177

def range(field, options = {})
  filter range: { field => options }
end

#search(q, options = {}) ⇒ ElasticSearch::Relation

Adds a query string query to the relation while using AND as the default operator unless otherwise specified. Check out the ElasticSearch docs for further details.

Examples:

CommentIndex.search("message:hello OR message:worl*")

Parameters:

  • q (String)

    The query string query

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

    Additional options for the query string query, like eg default_operator, default_field, etc.

Returns:


32
33
34
35
36
# File 'lib/elastic_search/filterable_relation.rb', line 32

def search(q, options = {})
  fresh.tap do |relation|
    relation.search_values = (search_values || []) + [query_string: { query: q, :default_operator => :AND }.merge(options)] if q.to_s.strip.length > 0
  end
end

#should(*args) ⇒ ElasticSearch::Relation

Adds raw should queries to the relation.

Examples:

CommentIndex.should(term: { state: "new" })
CommentIndex.should(range: { created_at: { gt: Time.parse"2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw should query arguments

Returns:


156
157
158
159
160
# File 'lib/elastic_search/filterable_relation.rb', line 156

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

#where(hash) ⇒ ElasticSearch::Relation

Adds filters to your relation for the supplied hash composed of field-to-filter mappings which specify terms, term or range filters, depending on the type of the respective hash value, namely array, range or scalar type like Fixnum, String, etc.

Examples:

CommentIndex.where(id: [1, 2, 3], state: ["approved", "declined"])
CommentIndex.where(id: 1 .. 100)
CommentIndex.where(created_at: Time.parse("2016-01-01") .. Time.parse("2017-01-01"))
CommentIndex.where(id: 1, message: "hello")

Parameters:

  • hash (Hash)

    A field-to-filter mapping specifying filter values for the respective fields

Returns:


54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/elastic_search/filterable_relation.rb', line 54

def where(hash)
  hash.inject(fresh) do |memo, (key, value)|
    if value.is_a?(Array)
      memo.filter terms: { key => value }
    elsif value.is_a?(Range)
      memo.filter range: { key => { gte: value.min, lte: value.max } }
    elsif value.nil?
      memo.exists_not key
    else
      memo.filter term: { key => value }
    end
  end
end

#where_not(hash) ⇒ ElasticSearch::Relation

Adds filters to exclude documents in accordance to the supplied hash composed of field-to-filter mappings. Check out #where for further details.

Examples:

CommentIndex.where_not(state: "approved")
CommentIndex.where_not(created_at: Time.parse("2016-01-01") .. Time.parse("2017-01-01"))
CommentIndex.where_not(id: [1, 2, 3], state: "new")

Parameters:

  • hash (Hash)

    A field-to-filter mapping specifying filter values for the respective fields

Returns:

See Also:


84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/elastic_search/filterable_relation.rb', line 84

def where_not(hash)
  hash.inject(fresh) do |memo, (key, value)|
    if value.is_a?(Array)
      memo.must_not terms: { key => value }
    elsif value.is_a?(Range)
      memo.must_not range: { key => { gte: value.min, lte: value.max } }
    elsif value.nil?
      memo.exists key
    else
      memo.must_not term: { key => value }
    end
  end
end