stretchy 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,241 +0,0 @@
1
- module Stretchy
2
- class Query
3
-
4
- DEFAULT_LIMIT = 40
5
-
6
- def initialize(options = {})
7
- @offset = options[:offset] || 0
8
- @limit = options[:limit] || DEFAULT_LIMIT
9
- @match = options[:match]
10
- @filters = options[:filters]
11
- @not_filters = options[:not_filters]
12
- @boosts = options[:boosts]
13
- @type = options[:type] || 'documents'
14
- @index = options[:index] || Stretchy.index_name
15
- @explain = options[:explain]
16
- end
17
-
18
- def clone_with(options)
19
- filters = [@filters, options[:filters], options[:filter]].flatten.compact
20
- not_filters = [@not_filters, options[:not_filters], options[:not_filter]].flatten.compact
21
- boosts = [@boosts, options[:boosts], options[:boost]].flatten.compact
22
-
23
- self.class.new(
24
- type: @type,
25
- index: @index,
26
- explain: options[:explain] || @explain,
27
- offset: options[:offset] || @offset,
28
- limit: options[:limit] || @limit,
29
- match: options[:match] || @match,
30
- filters: filters,
31
- not_filters: not_filters,
32
- boosts: boosts
33
- )
34
- end
35
-
36
- def offset(num)
37
- clone_with(offset: num)
38
- end
39
-
40
- def limit(num)
41
- clone_with(limit: num)
42
- end
43
-
44
- def explain
45
- clone_with(explain: true)
46
- end
47
-
48
- def where(options = {})
49
- return self if options.empty?
50
- filters, not_filters = where_clause(options)
51
- clone_with(filters: filters, not_filters: not_filters)
52
- end
53
-
54
- def not_where(options = {})
55
- return self if options.empty?
56
- # reverse the order returned here, since we're doing not_where
57
- not_filters, filters = where_clause(options)
58
- clone_with(filters: filters, not_filters: not_filters)
59
- end
60
-
61
- def boost_where(options = {})
62
- return self if options.empty?
63
- weight = options.delete(:weight) || 1.2
64
-
65
- boosts = options.map do |field, values|
66
- filter = nil
67
- if values.nil?
68
- filter = Filters::NotFilter.new(Filters::ExistsFilter.new(field))
69
- else
70
- filter = Filters::TermsFilter.new(field: field, values: Array(values))
71
- end
72
- Boosts::FilterBoost.new(filter: filter, weight: weight)
73
- end
74
- clone_with(boosts: boosts)
75
- end
76
-
77
- def boost_not_where(options = {})
78
- return self if options.empty?
79
- weight = options.delete(:weight) || 1.2
80
-
81
- boosts = []
82
- options.each do |field, values|
83
- filter = nil
84
- if values.nil?
85
- filter = Filters::ExistsFilter.new(field)
86
- elsif values.is_a?(Array)
87
- filter = NotFilter.new(Filters::TermsFilter.new(field: field, values: Array(values)))
88
- end
89
- Boosts::FilterBoost.new(filter: filter)
90
- end
91
- clone_with(boosts: boosts)
92
- end
93
-
94
- def range(field:, min: nil, max: nil)
95
- return self unless min || max
96
- clone_with(filter: Filters::RangeFilter.new(
97
- field: field,
98
- min: min,
99
- max: max
100
- ))
101
- end
102
-
103
- def not_range(field:, min: nil, max: nil)
104
- return self unless min || max
105
- clone_with(not_filter: Filters::RangeFilter.new(
106
- field: field,
107
- min: min,
108
- max: max
109
- ))
110
- end
111
-
112
- def boost_range(field:, min: nil, max: nil, weight: 1.2)
113
- return self unless min || max
114
- clone_with(boost: Boosts::Boost.new(
115
- filter: Filters::RangeFilter.new(
116
- field: field,
117
- min: min,
118
- max: max
119
- ),
120
- weight: weight
121
- ))
122
- end
123
-
124
- def geo(field: 'coords', distance: '50km', lat:, lng:)
125
- clone_with(filter: Filters::GeoFilter.new(
126
- field: field,
127
- distance: distance,
128
- lat: lat,
129
- lng: lng
130
- ))
131
- end
132
-
133
- def not_geo(field: 'coords', distance: '50km', lat:, lng:)
134
- clone_with(not_filter: Filters::GeoFilter.new(
135
- field: field,
136
- distance: distance,
137
- lat: lat,
138
- lng: lng
139
- ))
140
- end
141
-
142
- def boost_geo(options = {})
143
- return self if options.empty?
144
- clone_with(boost: Boosts::GeoBoost.new(options))
145
- end
146
-
147
- def match(string, options = {})
148
- return self if string.nil? || string.empty?
149
- field = options[:field] || '_all'
150
- operator = options[:operator] || 'and'
151
- clone_with(match: Queries::MatchQuery.new(string, field: field, operator: operator))
152
- end
153
-
154
- def not_match(string, options = {})
155
- field = options[:field] || '_all'
156
- operator = options[:operator] || 'and'
157
- clone_with(not_filter: Filters::QueryFilter.new(
158
- Queries::MatchQuery.new(string, field: field, operator: operator)
159
- ))
160
- end
161
-
162
- def boost_random(seed)
163
- clone_with(boost: Boosts::RandomBoost.new(seed))
164
- end
165
-
166
- def request
167
- @request ||= RequestBody.new(
168
- match: @match,
169
- filters: @filters,
170
- not_filters: @not_filters,
171
- boosts: @boosts,
172
- limit: @limit,
173
- offset: @offset,
174
- explain: @explain
175
- )
176
- end
177
-
178
- def response
179
- @response = Stretchy.search(type: @type, body: request.to_search)
180
- # caution: huuuuge logs, but pretty helpful
181
- # Rails.logger.debug(Colorize.purple(JSON.pretty_generate(@response)))
182
- @response
183
- end
184
-
185
- def id_response
186
- @id_response ||= Stretchy.search(type: @type, body: request.to_search, fields: [])
187
- # caution: huuuuge logs, but pretty helpful
188
- # Rails.logger.debug(Colorize.purple(JSON.pretty_generate(@id_response)))
189
- @id_response
190
- end
191
-
192
- def results
193
- @results ||= response['hits']['hits'].map do |hit|
194
- hit['_source'].merge(
195
- '_id' => hit['_id'],
196
- '_type' => hit['_type'],
197
- '_index' => hit['_index']
198
- )
199
- end
200
- end
201
-
202
- def ids
203
- @ids ||= result_metadata('hits', 'hits').map do |hit|
204
- hit['_id'].to_i == 0 ? hit['_id'] : hit['_id'].to_i
205
- end
206
- end
207
-
208
- def shards
209
- @shards ||= result_metadata('shards')
210
- end
211
-
212
- def total
213
- @total ||= result_metadata('hits', 'total')
214
- end
215
-
216
- private
217
- def result_metadata(*args)
218
- if @response
219
- args.reduce(@response){|json, field| json.nil? ? nil : json[field] }
220
- else
221
- args.reduce(id_response){|json, field| json.nil? ? nil : json[field] }
222
- end
223
- end
224
-
225
- def where_clause(options = {})
226
- return [[], []] if options.empty?
227
- filters = []
228
- not_filters = []
229
-
230
- options.each do |field, values|
231
- if values.nil?
232
- not_filters << Filters::ExistsFilter.new(field)
233
- else
234
- filters << Filters::TermsFilter.new(field: field, values: Array(values))
235
- end
236
- end
237
- [filters, not_filters]
238
- end
239
-
240
- end
241
- end
@@ -1,67 +0,0 @@
1
- module Stretchy
2
- class RequestBody
3
-
4
- def initialize(options = {})
5
- @json = {}
6
- @match = options[:match]
7
- @filters = Array(options[:filters])
8
- @not_filters = Array(options[:not_filters])
9
- @boosts = Array(options[:boosts])
10
- @offset = options[:offset] || 0
11
- @limit = options[:limit] || Query::DEFAULT_LIMIT
12
- @explain = options[:explain]
13
- end
14
-
15
- def to_search
16
- return @json unless @json.empty?
17
-
18
- query = @match || Queries::MatchAllQuery.new
19
-
20
- if @filters.any? && @not_filters.any?
21
- query = Queries::FilteredQuery.new(
22
- query: query,
23
- filter: Filters::BoolFilter.new(
24
- must: @filters,
25
- must_not: @not_filters
26
- )
27
- )
28
- elsif @filters.any?
29
- if @filters.count == 1
30
- query = Queries::FilteredQuery.new(
31
- query: query,
32
- filter: @filters.first
33
- )
34
- else
35
- query = Queries::FilteredQuery.new(
36
- query: query,
37
- filter: Filters::AndFilter.new(@filters)
38
- )
39
- end
40
- elsif @not_filters.any?
41
- query = Queries::FilteredQuery.new(
42
- query: query,
43
- filter: Filters::NotFilter.new(@not_filters)
44
- )
45
- end
46
-
47
- if @boosts.any?
48
- query = Queries::FunctionScoreQuery.new(
49
- query: query,
50
- functions: @boosts,
51
- score_mode: 'sum',
52
- boost_mode: 'max'
53
- )
54
- end
55
-
56
- @json = {}
57
- @json[:query] = query.to_search
58
- @json[:from] = @offset
59
- @json[:size] = @limit
60
- @json[:explain] = @explain if @explain
61
-
62
- # not a ton of output, usually worth having
63
- # puts "Generated elastic query: #{JSON.pretty_generate(@json)}"
64
- @json
65
- end
66
- end
67
- end