search_flip 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|