search_flip 2.2.0 → 2.3.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +14 -0
- data/README.md +32 -30
- data/lib/search_flip/aggregatable.rb +2 -2
- data/lib/search_flip/aggregation.rb +1 -1
- data/lib/search_flip/connection.rb +19 -19
- data/lib/search_flip/criteria.rb +47 -29
- data/lib/search_flip/filterable.rb +5 -3
- data/lib/search_flip/http_client.rb +1 -1
- data/lib/search_flip/index.rb +30 -30
- data/lib/search_flip/post_filterable.rb +2 -2
- data/lib/search_flip/response.rb +13 -13
- data/lib/search_flip/version.rb +1 -1
- data/search_flip.gemspec +3 -3
- data/spec/search_flip/criteria_spec.rb +58 -1
- data/spec/search_flip/index_spec.rb +1 -1
- metadata +9 -11
- data/logo.svg +0 -96
|
@@ -29,7 +29,7 @@ module SearchFlip
|
|
|
29
29
|
|
|
30
30
|
# Adds a post query string query to the criteria while using AND as the
|
|
31
31
|
# default operator unless otherwise specified. Check out the
|
|
32
|
-
#
|
|
32
|
+
# Elasticsearch docs for further details.
|
|
33
33
|
#
|
|
34
34
|
# @example
|
|
35
35
|
# CommentIndex.aggregate(:user_id).post_search("message:hello OR message:worl*")
|
|
@@ -201,7 +201,7 @@ module SearchFlip
|
|
|
201
201
|
# Adds a post range filter to the criteria without being forced to specify
|
|
202
202
|
# the left and right end of the range, such that you can eg simply specify
|
|
203
203
|
# lt, lte, gt and gte. For fully specified ranges, you can easily use
|
|
204
|
-
# #post_where, etc. Check out the
|
|
204
|
+
# #post_where, etc. Check out the Elasticsearch docs for further details
|
|
205
205
|
# regarding the range filter.
|
|
206
206
|
#
|
|
207
207
|
# @example
|
data/lib/search_flip/response.rb
CHANGED
|
@@ -11,14 +11,14 @@ module SearchFlip
|
|
|
11
11
|
# @api private
|
|
12
12
|
#
|
|
13
13
|
# Initializes a new response object for the provided criteria and raw
|
|
14
|
-
#
|
|
14
|
+
# Elasticsearch response.
|
|
15
15
|
|
|
16
16
|
def initialize(criteria, response)
|
|
17
17
|
self.criteria = criteria
|
|
18
18
|
self.response = response
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Returns the raw response, ie a hash derived from the
|
|
21
|
+
# Returns the raw response, ie a hash derived from the Elasticsearch JSON
|
|
22
22
|
# response.
|
|
23
23
|
#
|
|
24
24
|
# @example
|
|
@@ -198,25 +198,25 @@ module SearchFlip
|
|
|
198
198
|
end
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
-
# Returns the hits returned by
|
|
201
|
+
# Returns the hits returned by Elasticsearch.
|
|
202
202
|
#
|
|
203
203
|
# @example
|
|
204
204
|
# CommentIndex.search("hello world").hits
|
|
205
205
|
# # => {"total"=>3, "max_score"=>2.34, "hits"=>[{...}, ...]}
|
|
206
206
|
#
|
|
207
|
-
# @return [Hash] The hits returned by
|
|
207
|
+
# @return [Hash] The hits returned by Elasticsearch
|
|
208
208
|
|
|
209
209
|
def hits
|
|
210
210
|
response["hits"]
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
# Returns the scroll id returned by
|
|
213
|
+
# Returns the scroll id returned by Elasticsearch, that can be used in the
|
|
214
214
|
# following request to fetch the next batch of records.
|
|
215
215
|
#
|
|
216
216
|
# @example
|
|
217
217
|
# CommentIndex.scroll(timeout: "1m").scroll_id #=> "cXVlcnlUaGVuRmV0Y2..."
|
|
218
218
|
#
|
|
219
|
-
# @return [String] The scroll id returned by
|
|
219
|
+
# @return [String] The scroll id returned by Elasticsearch
|
|
220
220
|
|
|
221
221
|
def scroll_id
|
|
222
222
|
response["_scroll_id"]
|
|
@@ -224,7 +224,7 @@ module SearchFlip
|
|
|
224
224
|
|
|
225
225
|
# Returns the database records, usually ActiveRecord objects, depending on
|
|
226
226
|
# the ORM you're using. The records are sorted using the order returned by
|
|
227
|
-
#
|
|
227
|
+
# Elasticsearch.
|
|
228
228
|
#
|
|
229
229
|
# @example
|
|
230
230
|
# CommentIndex.search("hello world").records # => [#<Comment ...>, ...]
|
|
@@ -240,7 +240,7 @@ module SearchFlip
|
|
|
240
240
|
end
|
|
241
241
|
|
|
242
242
|
# Builds and returns a scope for the array of ids in the current result set
|
|
243
|
-
# returned by
|
|
243
|
+
# returned by Elasticsearch, including the eager load, preload and includes
|
|
244
244
|
# associations, if specified. A scope is eg an ActiveRecord::Relation,
|
|
245
245
|
# depending on the ORM you're using.
|
|
246
246
|
#
|
|
@@ -259,7 +259,7 @@ module SearchFlip
|
|
|
259
259
|
res
|
|
260
260
|
end
|
|
261
261
|
|
|
262
|
-
# Returns the array of ids returned by
|
|
262
|
+
# Returns the array of ids returned by Elasticsearch for the current result
|
|
263
263
|
# set, ie the ids listed in the hits section of the response.
|
|
264
264
|
#
|
|
265
265
|
# @example
|
|
@@ -273,19 +273,19 @@ module SearchFlip
|
|
|
273
273
|
|
|
274
274
|
def_delegators :ids, :size, :count, :length
|
|
275
275
|
|
|
276
|
-
# Returns the response time in milliseconds of
|
|
276
|
+
# Returns the response time in milliseconds of Elasticsearch specified in
|
|
277
277
|
# the took info of the response.
|
|
278
278
|
#
|
|
279
279
|
# @example
|
|
280
280
|
# CommentIndex.match_all.took # => 6
|
|
281
281
|
#
|
|
282
|
-
# @return [Fixnum] The
|
|
282
|
+
# @return [Fixnum] The Elasticsearch response time in milliseconds
|
|
283
283
|
|
|
284
284
|
def took
|
|
285
285
|
response["took"]
|
|
286
286
|
end
|
|
287
287
|
|
|
288
|
-
# Returns a single or all aggregations returned by
|
|
288
|
+
# Returns a single or all aggregations returned by Elasticsearch, depending
|
|
289
289
|
# on whether or not a name is specified. If no name is specified, the raw
|
|
290
290
|
# aggregation hash is simply returned. Contrary, if a name is specified,
|
|
291
291
|
# only this aggregation is returned. Moreover, if a name is specified and
|
|
@@ -300,7 +300,7 @@ module SearchFlip
|
|
|
300
300
|
# CommentIndex.aggregate(:user_id).aggregations(:user_id)
|
|
301
301
|
# # => {4922=>1129, ...}
|
|
302
302
|
#
|
|
303
|
-
# @return [Hash] Specific or all aggregations returned by
|
|
303
|
+
# @return [Hash] Specific or all aggregations returned by Elasticsearch
|
|
304
304
|
|
|
305
305
|
def aggregations(name = nil)
|
|
306
306
|
return response["aggregations"] || {} unless name
|
data/lib/search_flip/version.rb
CHANGED
data/search_flip.gemspec
CHANGED
|
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.version = SearchFlip::VERSION
|
|
10
10
|
spec.authors = ["Benjamin Vetter"]
|
|
11
11
|
spec.email = ["vetter@flakks.com"]
|
|
12
|
-
spec.description = %q{
|
|
13
|
-
spec.summary = %q{
|
|
12
|
+
spec.description = %q{Full-Featured Elasticsearch Ruby Client with a Chainable DSL}
|
|
13
|
+
spec.summary = %q{Full-Featured Elasticsearch Ruby Client with a Chainable DSL}
|
|
14
14
|
spec.homepage = "https://github.com/mrkamel/search_flip"
|
|
15
15
|
spec.license = "MIT"
|
|
16
16
|
|
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.add_development_dependency "factory_bot"
|
|
31
31
|
spec.add_development_dependency "rake"
|
|
32
32
|
spec.add_development_dependency "rspec"
|
|
33
|
-
spec.add_development_dependency "sqlite3"
|
|
33
|
+
spec.add_development_dependency "sqlite3"
|
|
34
34
|
spec.add_development_dependency "timecop"
|
|
35
35
|
spec.add_development_dependency "webmock"
|
|
36
36
|
|
|
@@ -36,7 +36,7 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
36
36
|
methods = [
|
|
37
37
|
:profile_value, :failsafe_value, :terminate_after_value, :timeout_value,
|
|
38
38
|
:offset_value, :limit_value, :scroll_args, :source_value, :preference_value,
|
|
39
|
-
:search_type_value, :routing_value, :track_total_hits_value
|
|
39
|
+
:search_type_value, :routing_value, :track_total_hits_value, :explain_value
|
|
40
40
|
]
|
|
41
41
|
|
|
42
42
|
methods.each do |method|
|
|
@@ -259,6 +259,54 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
259
259
|
end
|
|
260
260
|
end
|
|
261
261
|
|
|
262
|
+
describe "#must" do
|
|
263
|
+
it "sets up the constraints correctly and is chainable" do
|
|
264
|
+
product1 = create(:product, price: 100, category: "category1")
|
|
265
|
+
product2 = create(:product, price: 200, category: "category2")
|
|
266
|
+
product3 = create(:product, price: 300, category: "category1")
|
|
267
|
+
|
|
268
|
+
ProductIndex.import [product1, product2, product3]
|
|
269
|
+
|
|
270
|
+
query1 = ProductIndex.must(range: { price: { gte: 100, lte: 200 } })
|
|
271
|
+
query2 = query1.must(term: { category: "category1" })
|
|
272
|
+
|
|
273
|
+
expect(query1.records.to_set).to eq([product1, product2].to_set)
|
|
274
|
+
expect(query2.records).to eq([product1])
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe "#must_not" do
|
|
279
|
+
it "sets up the constraints correctly and is chainable" do
|
|
280
|
+
product1 = create(:product, price: 100, category: "category1")
|
|
281
|
+
product2 = create(:product, price: 200, category: "category2")
|
|
282
|
+
product3 = create(:product, price: 300, category: "category1")
|
|
283
|
+
|
|
284
|
+
ProductIndex.import [product1, product2, product3]
|
|
285
|
+
|
|
286
|
+
query1 = ProductIndex.must_not(range: { price: { gt: 200, lte: 300 } })
|
|
287
|
+
query2 = query1.must_not(term: { category: "category2" })
|
|
288
|
+
|
|
289
|
+
expect(query1.records.to_set).to eq([product1, product2].to_set)
|
|
290
|
+
expect(query2.records).to eq([product1])
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
describe "#should" do
|
|
295
|
+
it "sets up the constraints correctly and is chainable" do
|
|
296
|
+
product1 = create(:product, price: 100, category: "category1")
|
|
297
|
+
product2 = create(:product, price: 200, category: "category2")
|
|
298
|
+
product3 = create(:product, price: 300, category: "category1")
|
|
299
|
+
|
|
300
|
+
ProductIndex.import [product1, product2, product3]
|
|
301
|
+
|
|
302
|
+
query1 = ProductIndex.should(range: { price: { gte: 100, lt: 200 } })
|
|
303
|
+
query2 = query1.should(term: { category: "category2" })
|
|
304
|
+
|
|
305
|
+
expect(query1.records.to_set).to eq([product1].to_set)
|
|
306
|
+
expect(query2.records.to_set).to eq([product1, product2].to_set)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
262
310
|
describe "#range" do
|
|
263
311
|
it "sets up the constraints correctly and is chainable" do
|
|
264
312
|
product1 = create(:product, price: 100)
|
|
@@ -1035,6 +1083,15 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
1035
1083
|
end
|
|
1036
1084
|
end
|
|
1037
1085
|
|
|
1086
|
+
describe "#explain" do
|
|
1087
|
+
it "returns the explaination" do
|
|
1088
|
+
ProductIndex.import create(:product)
|
|
1089
|
+
|
|
1090
|
+
query = ProductIndex.match_all.explain(true)
|
|
1091
|
+
expect(query.results.first._hit.key?(:_explanation)).to eq(true)
|
|
1092
|
+
end
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1038
1095
|
describe "#custom" do
|
|
1039
1096
|
it "adds a custom entry to the request" do
|
|
1040
1097
|
request = ProductIndex.custom(custom_key: "custom_value").request
|
|
@@ -15,7 +15,7 @@ RSpec.describe SearchFlip::Index do
|
|
|
15
15
|
:total_entries, :total_count, :terminate_after, :timeout, :records, :results,
|
|
16
16
|
:should, :should_not, :must, :must_not, :find_each_result,
|
|
17
17
|
:find_results_in_batches, :preference, :search_type, :routing,
|
|
18
|
-
:track_total_hits
|
|
18
|
+
:track_total_hits, :explain
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
methods.each do |method|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: search_flip
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Benjamin Vetter
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-08-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -84,16 +84,16 @@ dependencies:
|
|
|
84
84
|
name: sqlite3
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- - "
|
|
87
|
+
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
89
|
+
version: '0'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- - "
|
|
94
|
+
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
96
|
+
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
98
|
name: timecop
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -164,7 +164,7 @@ dependencies:
|
|
|
164
164
|
- - ">="
|
|
165
165
|
- !ruby/object:Gem::Version
|
|
166
166
|
version: '0'
|
|
167
|
-
description:
|
|
167
|
+
description: Full-Featured Elasticsearch Ruby Client with a Chainable DSL
|
|
168
168
|
email:
|
|
169
169
|
- vetter@flakks.com
|
|
170
170
|
executables: []
|
|
@@ -199,7 +199,6 @@ files:
|
|
|
199
199
|
- lib/search_flip/result.rb
|
|
200
200
|
- lib/search_flip/to_json.rb
|
|
201
201
|
- lib/search_flip/version.rb
|
|
202
|
-
- logo.svg
|
|
203
202
|
- search_flip.gemspec
|
|
204
203
|
- spec/delegate_matcher.rb
|
|
205
204
|
- spec/search_flip/aggregation_spec.rb
|
|
@@ -234,11 +233,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
234
233
|
- !ruby/object:Gem::Version
|
|
235
234
|
version: '0'
|
|
236
235
|
requirements: []
|
|
237
|
-
|
|
238
|
-
rubygems_version: 2.7.3
|
|
236
|
+
rubygems_version: 3.0.3
|
|
239
237
|
signing_key:
|
|
240
238
|
specification_version: 4
|
|
241
|
-
summary:
|
|
239
|
+
summary: Full-Featured Elasticsearch Ruby Client with a Chainable DSL
|
|
242
240
|
test_files:
|
|
243
241
|
- spec/delegate_matcher.rb
|
|
244
242
|
- spec/search_flip/aggregation_spec.rb
|
data/logo.svg
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!-- Generated by IcoMoon.io -->
|
|
3
|
-
|
|
4
|
-
<svg
|
|
5
|
-
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
6
|
-
xmlns:cc="http://creativecommons.org/ns#"
|
|
7
|
-
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
8
|
-
xmlns:svg="http://www.w3.org/2000/svg"
|
|
9
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
-
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
11
|
-
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
12
|
-
version="1.1"
|
|
13
|
-
width="300"
|
|
14
|
-
height="50"
|
|
15
|
-
viewBox="0 0 299.99998 50"
|
|
16
|
-
id="svg4869"
|
|
17
|
-
sodipodi:docname="logo.svg"
|
|
18
|
-
inkscape:export-filename="/home/hkf/projects/search_flip/logo.png"
|
|
19
|
-
inkscape:export-xdpi="299.34824"
|
|
20
|
-
inkscape:export-ydpi="299.34824"
|
|
21
|
-
inkscape:version="0.92.1 r15371">
|
|
22
|
-
<metadata
|
|
23
|
-
id="metadata4875">
|
|
24
|
-
<rdf:RDF>
|
|
25
|
-
<cc:Work
|
|
26
|
-
rdf:about="">
|
|
27
|
-
<dc:format>image/svg+xml</dc:format>
|
|
28
|
-
<dc:type
|
|
29
|
-
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
30
|
-
<dc:title>arrow-long-up</dc:title>
|
|
31
|
-
</cc:Work>
|
|
32
|
-
</rdf:RDF>
|
|
33
|
-
</metadata>
|
|
34
|
-
<defs
|
|
35
|
-
id="defs4873" />
|
|
36
|
-
<sodipodi:namedview
|
|
37
|
-
pagecolor="#ffffff"
|
|
38
|
-
bordercolor="#666666"
|
|
39
|
-
borderopacity="1"
|
|
40
|
-
objecttolerance="10"
|
|
41
|
-
gridtolerance="10"
|
|
42
|
-
guidetolerance="10"
|
|
43
|
-
inkscape:pageopacity="0"
|
|
44
|
-
inkscape:pageshadow="2"
|
|
45
|
-
inkscape:window-width="1920"
|
|
46
|
-
inkscape:window-height="971"
|
|
47
|
-
id="namedview4871"
|
|
48
|
-
showgrid="false"
|
|
49
|
-
fit-margin-top="0"
|
|
50
|
-
fit-margin-left="0"
|
|
51
|
-
fit-margin-right="0"
|
|
52
|
-
fit-margin-bottom="0"
|
|
53
|
-
inkscape:zoom="2.085965"
|
|
54
|
-
inkscape:cx="91.987216"
|
|
55
|
-
inkscape:cy="-41.606043"
|
|
56
|
-
inkscape:window-x="0"
|
|
57
|
-
inkscape:window-y="31"
|
|
58
|
-
inkscape:window-maximized="1"
|
|
59
|
-
inkscape:current-layer="svg4869" />
|
|
60
|
-
<title
|
|
61
|
-
id="title4865">arrow-long-up</title>
|
|
62
|
-
<path
|
|
63
|
-
d="M 39.922489,4.151999 36.230955,18.361869 32.37339,14.504302 10.209748,36.667943 7.4576271,33.915823 29.621268,11.75218 25.712619,7.843531 Z"
|
|
64
|
-
id="path4867"
|
|
65
|
-
inkscape:connector-curvature="0"
|
|
66
|
-
style="stroke-width:1.80568123"
|
|
67
|
-
inkscape:export-xdpi="325.4834"
|
|
68
|
-
inkscape:export-ydpi="325.4834"
|
|
69
|
-
sodipodi:nodetypes="cccccccc"
|
|
70
|
-
inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png" />
|
|
71
|
-
<path
|
|
72
|
-
d="M 17.625202,45.376517 31.473864,41.323778 27.948317,37.696072 50.111962,15.532428 47.418207,12.940838 25.254566,35.10448 21.677941,31.527854 Z"
|
|
73
|
-
id="path4867-7"
|
|
74
|
-
inkscape:connector-curvature="0"
|
|
75
|
-
style="stroke-width:1.74257004"
|
|
76
|
-
inkscape:export-xdpi="325.4834"
|
|
77
|
-
inkscape:export-ydpi="325.4834"
|
|
78
|
-
sodipodi:nodetypes="cccccccc"
|
|
79
|
-
inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png" />
|
|
80
|
-
<text
|
|
81
|
-
xml:space="preserve"
|
|
82
|
-
style="font-style:normal;font-weight:normal;font-size:96.44345093px;line-height:1.25;font-family:sans-serif;letter-spacing:-0.65099335px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.41108632"
|
|
83
|
-
x="59.037937"
|
|
84
|
-
y="37.501484"
|
|
85
|
-
id="text4908"
|
|
86
|
-
inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png"
|
|
87
|
-
inkscape:export-xdpi="325.4834"
|
|
88
|
-
inkscape:export-ydpi="325.4834"
|
|
89
|
-
inkscape:transform-center-x="-2.0432889"
|
|
90
|
-
inkscape:transform-center-y="-9.8078108"><tspan
|
|
91
|
-
sodipodi:role="line"
|
|
92
|
-
id="tspan4906"
|
|
93
|
-
x="59.037937"
|
|
94
|
-
y="37.501484"
|
|
95
|
-
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:51.43650818px;line-height:6;font-family:'times new roman';-inkscape-font-specification:'times new roman, ';letter-spacing:0px;word-spacing:-19.48158455px;stroke-width:2.41108632">search_flip</tspan></text>
|
|
96
|
-
</svg>
|