Class: Stretchy::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/stretchy/query.rb

Constant Summary collapse

DEFAULT_LIMIT =
40

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Query

Returns a new instance of Query.



6
7
8
9
10
11
12
13
14
15
16
# File 'lib/stretchy/query.rb', line 6

def initialize(options = {})
  @offset       = options[:offset]      || 0
  @limit        = options[:limit]       || DEFAULT_LIMIT
  @match        = options[:match]
  @filters      = options[:filters]
  @not_filters  = options[:not_filters]
  @boosts       = options[:boosts]
  @type         = options[:type]        || 'documents'
  @index        = options[:index]       || Stretchy.index_name
  @explain      = options[:explain]
end

Instance Method Details

#boost_geo(options = {}) ⇒ Object



142
143
144
145
# File 'lib/stretchy/query.rb', line 142

def boost_geo(options = {})
  return self if options.empty?
  clone_with(boost: Boosts::GeoBoost.new(options))
end

#boost_not_where(options = {}) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/stretchy/query.rb', line 77

def boost_not_where(options = {})
  return self if options.empty?
  weight = options.delete(:weight) || 1.2

  boosts = []
  options.each do |field, values|
    filter = nil
    if values.nil?
      filter = Filters::ExistsFilter.new(field)
    elsif values.is_a?(Array)
      filter = NotFilter.new(Filters::TermsFilter.new(field: field, values: Array(values)))
    end
    Boosts::FilterBoost.new(filter: filter)
  end
  clone_with(boosts: boosts)
end

#boost_random(seed) ⇒ Object



162
163
164
# File 'lib/stretchy/query.rb', line 162

def boost_random(seed)
  clone_with(boost: Boosts::RandomBoost.new(seed))
end

#boost_range(field:, min: nil, max: nil, weight: 1.2) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/stretchy/query.rb', line 112

def boost_range(field:, min: nil, max: nil, weight: 1.2)
  return self unless min || max
  clone_with(boost: Boosts::Boost.new(
    filter: Filters::RangeFilter.new(
      field: field,
      min: min,
      max: max
    ),
    weight: weight
  ))
end

#boost_where(options = {}) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/stretchy/query.rb', line 61

def boost_where(options = {})
  return self if options.empty?
  weight = options.delete(:weight) || 1.2

  boosts = options.map do |field, values|
    filter = nil
    if values.nil?
      filter = Filters::NotFilter.new(Filters::ExistsFilter.new(field))
    else
      filter = Filters::TermsFilter.new(field: field, values: Array(values))
    end
    Boosts::FilterBoost.new(filter: filter, weight: weight)
  end
  clone_with(boosts: boosts)
end

#clone_with(options) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/stretchy/query.rb', line 18

def clone_with(options)
  filters     = [@filters, options[:filters], options[:filter]].flatten.compact
  not_filters = [@not_filters, options[:not_filters], options[:not_filter]].flatten.compact
  boosts      = [@boosts, options[:boosts], options[:boost]].flatten.compact

  self.class.new(
    type:         @type,
    index:        @index,
    explain:      options[:explain] || @explain,
    offset:       options[:offset]  || @offset,
    limit:        options[:limit]   || @limit,
    match:        options[:match]   || @match,
    filters:      filters,
    not_filters:  not_filters,
    boosts:       boosts
  )
end

#explainObject



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

def explain
  clone_with(explain: true)
end

#geo(field: 'coords', distance: '50km', lat:, lng:) ⇒ Object



124
125
126
127
128
129
130
131
# File 'lib/stretchy/query.rb', line 124

def geo(field: 'coords', distance: '50km', lat:, lng:)
  clone_with(filter: Filters::GeoFilter.new(
    field: field,
    distance: distance,
    lat: lat,
    lng: lng
  ))
end

#id_responseObject



185
186
187
188
189
190
# File 'lib/stretchy/query.rb', line 185

def id_response
  @id_response ||= Stretchy.search(type: @type, body: request.to_search, fields: [])
  # caution: huuuuge logs, but pretty helpful
  # Rails.logger.debug(Colorize.purple(JSON.pretty_generate(@id_response)))
  @id_response
end

#idsObject



202
203
204
205
206
# File 'lib/stretchy/query.rb', line 202

def ids
  @ids ||= ('hits', 'hits').map do |hit| 
    hit['_id'].to_i == 0 ? hit['_id'] : hit['_id'].to_i
  end
end

#limit(num) ⇒ Object



40
41
42
# File 'lib/stretchy/query.rb', line 40

def limit(num)
  clone_with(limit: num)
end

#match(string, options = {}) ⇒ Object



147
148
149
150
151
152
# File 'lib/stretchy/query.rb', line 147

def match(string, options = {})
  return self if string.nil? || string.empty?
  field     = options[:field] || '_all'
  operator  = options[:operator] || 'and'
  clone_with(match: Queries::MatchQuery.new(string, field: field, operator: operator))
end

#not_geo(field: 'coords', distance: '50km', lat:, lng:) ⇒ Object



133
134
135
136
137
138
139
140
# File 'lib/stretchy/query.rb', line 133

def not_geo(field: 'coords', distance: '50km', lat:, lng:)
  clone_with(not_filter: Filters::GeoFilter.new(
    field: field,
    distance: distance,
    lat: lat,
    lng: lng
  ))
end

#not_match(string, options = {}) ⇒ Object



154
155
156
157
158
159
160
# File 'lib/stretchy/query.rb', line 154

def not_match(string, options = {})
  field = options[:field] || '_all'
  operator = options[:operator] || 'and'
  clone_with(not_filter: Filters::QueryFilter.new(
    Queries::MatchQuery.new(string, field: field, operator: operator)
  ))
end

#not_range(field:, min: nil, max: nil) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/stretchy/query.rb', line 103

def not_range(field:, min: nil, max: nil)
  return self unless min || max
  clone_with(not_filter: Filters::RangeFilter.new(
    field: field,
    min: min,
    max: max
  ))
end

#not_where(options = {}) ⇒ Object



54
55
56
57
58
59
# File 'lib/stretchy/query.rb', line 54

def not_where(options = {})
  return self if options.empty?
  # reverse the order returned here, since we're doing not_where
  not_filters, filters = where_clause(options)
  clone_with(filters: filters, not_filters: not_filters)
end

#offset(num) ⇒ Object



36
37
38
# File 'lib/stretchy/query.rb', line 36

def offset(num)
  clone_with(offset: num)
end

#range(field:, min: nil, max: nil) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/stretchy/query.rb', line 94

def range(field:, min: nil, max: nil)
  return self unless min || max
  clone_with(filter: Filters::RangeFilter.new(
    field: field,
    min: min,
    max: max
  ))
end

#requestObject



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/stretchy/query.rb', line 166

def request
  @request ||= RequestBody.new(
    match:        @match,
    filters:      @filters,
    not_filters:  @not_filters,
    boosts:       @boosts,
    limit:        @limit,
    offset:       @offset,
    explain:      @explain
  )
end

#responseObject



178
179
180
181
182
183
# File 'lib/stretchy/query.rb', line 178

def response
  @response = Stretchy.search(type: @type, body: request.to_search)
  # caution: huuuuge logs, but pretty helpful
  # Rails.logger.debug(Colorize.purple(JSON.pretty_generate(@response)))
  @response
end

#resultsObject



192
193
194
195
196
197
198
199
200
# File 'lib/stretchy/query.rb', line 192

def results
  @results ||= response['hits']['hits'].map do |hit|
    hit['_source'].merge(
      '_id' => hit['_id'],
      '_type' => hit['_type'],
      '_index' => hit['_index']
    )
  end
end

#shardsObject



208
209
210
# File 'lib/stretchy/query.rb', line 208

def shards
  @shards ||= ('shards')
end

#totalObject



212
213
214
# File 'lib/stretchy/query.rb', line 212

def total
  @total  ||= ('hits', 'total')
end

#where(options = {}) ⇒ Object



48
49
50
51
52
# File 'lib/stretchy/query.rb', line 48

def where(options = {})
  return self if options.empty?
  filters, not_filters = where_clause(options)
  clone_with(filters: filters, not_filters: not_filters)
end