search_flip 2.0.0.beta2 → 2.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -3
- data/README.md +22 -1
- data/UPDATING.md +21 -5
- data/lib/search_flip/bulk.rb +5 -2
- data/lib/search_flip/connection.rb +29 -19
- data/lib/search_flip/criteria.rb +48 -18
- data/lib/search_flip/http_client.rb +27 -26
- data/lib/search_flip/index.rb +6 -4
- data/lib/search_flip/response.rb +9 -1
- data/lib/search_flip/version.rb +1 -1
- data/search_flip.gemspec +7 -2
- data/spec/delegate_matcher.rb +32 -0
- data/spec/search_flip/aggregation_spec.rb +265 -0
- data/spec/search_flip/bulk_spec.rb +78 -0
- data/spec/search_flip/connection_spec.rb +211 -0
- data/spec/search_flip/criteria_spec.rb +1028 -0
- data/spec/search_flip/http_client_spec.rb +67 -0
- data/spec/search_flip/index_spec.rb +455 -0
- data/spec/search_flip/model_spec.rb +44 -0
- data/spec/search_flip/response_spec.rb +185 -0
- data/spec/search_flip/to_json_spec.rb +29 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +13 -76
- metadata +30 -39
- data/test/search_flip/aggregation_test.rb +0 -230
- data/test/search_flip/bulk_test.rb +0 -55
- data/test/search_flip/connection_test.rb +0 -161
- data/test/search_flip/criteria_test.rb +0 -879
- data/test/search_flip/http_client_test.rb +0 -35
- data/test/search_flip/index_test.rb +0 -451
- data/test/search_flip/model_test.rb +0 -39
- data/test/search_flip/response_test.rb +0 -137
- data/test/search_flip/to_json_test.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55f88fe9b429304c6f605a0175b3b711334cf47613facc78864511b012e2eb4e
|
4
|
+
data.tar.gz: 12c5e164eb18caaf72a361c7d1ba24f9b0324c412f2c7712f79f87e9248dbf1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26842b8df4ee2014ee77f1429ab6438350f45458e150fe1786f654bb2d925c53524007d2ec88bed42f80d0983887b8720c19b617ec1e00de8de8964c70a602dd
|
7
|
+
data.tar.gz: 6976b12cd544bbc19f88fb69e855c6107badd49c565578b6b5a75b07d63d85ad4d85762e0e18b02010b9376123f44c8bb73dc81676e3f28cdd5b9ab9d237659c
|
data/.rubocop.yml
CHANGED
@@ -47,10 +47,10 @@ Layout/LeadingBlankLines:
|
|
47
47
|
Enabled: false
|
48
48
|
|
49
49
|
Metrics/LineLength:
|
50
|
-
|
50
|
+
Enabled: false
|
51
51
|
|
52
52
|
Metrics/MethodLength:
|
53
|
-
|
53
|
+
Enabled: false
|
54
54
|
|
55
55
|
Metrics/ModuleLength:
|
56
56
|
Enabled: false
|
@@ -71,7 +71,7 @@ Metrics/CyclomaticComplexity:
|
|
71
71
|
Enabled: false
|
72
72
|
|
73
73
|
Metrics/BlockLength:
|
74
|
-
|
74
|
+
Enabled: false
|
75
75
|
|
76
76
|
Metrics/BlockNesting:
|
77
77
|
Enabled: false
|
@@ -108,3 +108,10 @@ Lint/UnusedMethodArgument:
|
|
108
108
|
|
109
109
|
Layout/IndentArray:
|
110
110
|
EnforcedStyle: consistent
|
111
|
+
|
112
|
+
Style/IfUnlessModifier:
|
113
|
+
Enabled: false
|
114
|
+
|
115
|
+
Style/RedundantBegin:
|
116
|
+
Enabled: false
|
117
|
+
|
data/README.md
CHANGED
@@ -373,7 +373,7 @@ CommentIndex.highlight(title: { type: "fvh" })
|
|
373
373
|
|
374
374
|
```ruby
|
375
375
|
query = CommentIndex.highlight(:title).search("hello")
|
376
|
-
query.results[0].highlight.title # => "<em>hello</em> world"
|
376
|
+
query.results[0]._hit.highlight.title # => "<em>hello</em> world"
|
377
377
|
```
|
378
378
|
|
379
379
|
### Advanced Criteria Methods
|
@@ -558,6 +558,27 @@ end
|
|
558
558
|
This allows to use different clusters per index e.g. when migrating indices to
|
559
559
|
new versions of Elasticsearch.
|
560
560
|
|
561
|
+
## Routing and other index-time options
|
562
|
+
|
563
|
+
Override `index_options` in case you want to use routing or pass other
|
564
|
+
index-time options:
|
565
|
+
|
566
|
+
```ruby
|
567
|
+
class CommentIndex
|
568
|
+
include SearchFlip::Index
|
569
|
+
|
570
|
+
def self.index_options(comment)
|
571
|
+
{
|
572
|
+
routing: comment.user_id,
|
573
|
+
version: comment.version,
|
574
|
+
version_type: "external_gte"
|
575
|
+
}
|
576
|
+
end
|
577
|
+
end
|
578
|
+
```
|
579
|
+
|
580
|
+
These options will be passed whenever records get indexed, deleted, etc.
|
581
|
+
|
561
582
|
## Non-ActiveRecord models
|
562
583
|
|
563
584
|
SearchFlip ships with built-in support for ActiveRecord models, but using
|
data/UPDATING.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
## Update 1.x to 2.x
|
5
5
|
|
6
|
-
* [BREAKING] Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
|
6
|
+
* **[BREAKING]** Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
|
7
7
|
|
8
8
|
1.x:
|
9
9
|
|
@@ -33,7 +33,7 @@ class MyIndex
|
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
-
* [BREAKING] Changed `SearchFlip.version` to `SearchFlip::Connection#version`
|
36
|
+
* **[BREAKING]** Changed `SearchFlip.version` to `SearchFlip::Connection#version`
|
37
37
|
|
38
38
|
1.x:
|
39
39
|
|
@@ -52,7 +52,7 @@ connection = SearchFlip::Connection.new(base_url: "...")
|
|
52
52
|
connection.version
|
53
53
|
```
|
54
54
|
|
55
|
-
* [BREAKING] Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
|
55
|
+
* **[BREAKING]** Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
|
56
56
|
|
57
57
|
1.x:
|
58
58
|
|
@@ -77,7 +77,7 @@ connection.update_aliases(actions: [
|
|
77
77
|
])
|
78
78
|
```
|
79
79
|
|
80
|
-
* [BREAKING] Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
|
80
|
+
* **[BREAKING]** Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
|
81
81
|
|
82
82
|
1.x:
|
83
83
|
|
@@ -96,7 +96,7 @@ connection = SearchFlip::Connection.new(base_url: "...")
|
|
96
96
|
connection.msearch(queries)
|
97
97
|
```
|
98
98
|
|
99
|
-
* [BREAKING] Removed `base_url` param from `SearchFlip::Critiera#execute`
|
99
|
+
* **[BREAKING]** Removed `base_url` param from `SearchFlip::Critiera#execute`
|
100
100
|
|
101
101
|
1.x:
|
102
102
|
|
@@ -111,3 +111,19 @@ connection = SearchFlip::Connection.new(base_url: "...")
|
|
111
111
|
MyIndex.where(id: 1).with_settings(connection: connection).execute
|
112
112
|
```
|
113
113
|
|
114
|
+
* **[BREAKING]** Move hit data within results in `_hit` namespace
|
115
|
+
|
116
|
+
1.x:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
query = CommentIndex.highlight(:title).search("hello")
|
120
|
+
query.results[0].highlight.title # => "<em>hello</em> world"
|
121
|
+
```
|
122
|
+
|
123
|
+
2.x:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
query = CommentIndex.highlight(:title).search("hello")
|
127
|
+
query.results[0]._hit.highlight.title # => "<em>hello</em> world"
|
128
|
+
```
|
129
|
+
|
data/lib/search_flip/bulk.rb
CHANGED
@@ -14,7 +14,7 @@ module SearchFlip
|
|
14
14
|
class Bulk
|
15
15
|
class Error < StandardError; end
|
16
16
|
|
17
|
-
attr_accessor :url, :count, :options, :ignore_errors
|
17
|
+
attr_accessor :url, :count, :options, :http_client, :ignore_errors
|
18
18
|
|
19
19
|
# Builds and yields a new Bulk object, ie initiates the buffer, yields,
|
20
20
|
# sends batches of records each time the buffer is full, and sends a final
|
@@ -40,11 +40,14 @@ module SearchFlip
|
|
40
40
|
# @option options raise [Boolean] If you want the bulk requests to never
|
41
41
|
# raise any exceptions (fire and forget), you can pass false here.
|
42
42
|
# Default is true.
|
43
|
+
# @option options http_client [SearchFlip::HTTPClient] An optional http
|
44
|
+
# client instance
|
43
45
|
|
44
46
|
def initialize(url, count = 1_000, options = {})
|
45
47
|
self.url = url
|
46
48
|
self.count = count
|
47
49
|
self.options = options
|
50
|
+
self.http_client = options[:http_client] || SearchFlip::HTTPClient.new
|
48
51
|
self.ignore_errors = Array(options[:ignore_errors]).to_set if options[:ignore_errors]
|
49
52
|
|
50
53
|
init
|
@@ -114,7 +117,7 @@ module SearchFlip
|
|
114
117
|
|
115
118
|
def upload
|
116
119
|
response =
|
117
|
-
|
120
|
+
http_client
|
118
121
|
.headers(accept: "application/json", content_type: "application/x-ndjson")
|
119
122
|
.put(url, body: @payload, params: ignore_errors ? {} : { filter_path: "errors" })
|
120
123
|
|
@@ -1,10 +1,19 @@
|
|
1
1
|
|
2
2
|
module SearchFlip
|
3
3
|
class Connection
|
4
|
-
attr_reader :base_url
|
4
|
+
attr_reader :base_url, :http_client
|
5
5
|
|
6
|
-
|
6
|
+
# Creates a new connection.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SearchFlip::Connection.new(base_url: "http://elasticsearch.host:9200")
|
10
|
+
#
|
11
|
+
# @param base_url [String] The base url for the connection
|
12
|
+
# @param http_client [SearchFlip::HTTPClient] An optional http client instance
|
13
|
+
|
14
|
+
def initialize(base_url: SearchFlip::Config[:base_url], http_client: SearchFlip::HTTPClient.new)
|
7
15
|
@base_url = base_url
|
16
|
+
@http_client = http_client
|
8
17
|
end
|
9
18
|
|
10
19
|
# Queries and returns the ElasticSearch version used.
|
@@ -15,7 +24,7 @@ module SearchFlip
|
|
15
24
|
# @return [String] The ElasticSearch version
|
16
25
|
|
17
26
|
def version
|
18
|
-
@version ||=
|
27
|
+
@version ||= http_client.headers(accept: "application/json").get("#{base_url}/").parse["version"]["number"]
|
19
28
|
end
|
20
29
|
|
21
30
|
# Uses the ElasticSearch Multi Search API to execute multiple search requests
|
@@ -42,7 +51,7 @@ module SearchFlip
|
|
42
51
|
payload << "\n"
|
43
52
|
|
44
53
|
raw_response =
|
45
|
-
|
54
|
+
http_client
|
46
55
|
.headers(accept: "application/json", content_type: "application/x-ndjson")
|
47
56
|
.post("#{base_url}/_msearch", body: payload)
|
48
57
|
|
@@ -65,7 +74,7 @@ module SearchFlip
|
|
65
74
|
# @return [Hash] The raw response
|
66
75
|
|
67
76
|
def update_aliases(payload)
|
68
|
-
|
77
|
+
http_client
|
69
78
|
.headers(accept: "application/json", content_type: "application/json")
|
70
79
|
.post("#{base_url}/_aliases", body: SearchFlip::JSON.generate(payload))
|
71
80
|
.parse
|
@@ -84,10 +93,11 @@ module SearchFlip
|
|
84
93
|
# @return [Hash] The raw response
|
85
94
|
|
86
95
|
def get_aliases(index_name: "*", alias_name: "*")
|
87
|
-
res =
|
88
|
-
|
89
|
-
|
90
|
-
|
96
|
+
res =
|
97
|
+
http_client
|
98
|
+
.headers(accept: "application/json", content_type: "application/json")
|
99
|
+
.get("#{base_url}/#{index_name}/_alias/#{alias_name}")
|
100
|
+
.parse
|
91
101
|
|
92
102
|
Hashie::Mash.new(res)
|
93
103
|
end
|
@@ -101,7 +111,7 @@ module SearchFlip
|
|
101
111
|
# @return [Boolean] Whether or not the alias exists
|
102
112
|
|
103
113
|
def alias_exists?(alias_name)
|
104
|
-
|
114
|
+
http_client
|
105
115
|
.headers(accept: "application/json", content_type: "application/json")
|
106
116
|
.get("#{base_url}/_alias/#{alias_name}")
|
107
117
|
|
@@ -121,7 +131,7 @@ module SearchFlip
|
|
121
131
|
# @return [Array] The raw response
|
122
132
|
|
123
133
|
def get_indices(name = "*")
|
124
|
-
|
134
|
+
http_client
|
125
135
|
.headers(accept: "application/json", content_type: "application/json")
|
126
136
|
.get("#{base_url}/_cat/indices/#{name}")
|
127
137
|
.parse
|
@@ -136,7 +146,7 @@ module SearchFlip
|
|
136
146
|
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
137
147
|
|
138
148
|
def create_index(index_name, index_settings = {})
|
139
|
-
|
149
|
+
http_client.put(index_url(index_name), json: index_settings)
|
140
150
|
|
141
151
|
true
|
142
152
|
end
|
@@ -150,7 +160,7 @@ module SearchFlip
|
|
150
160
|
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
151
161
|
|
152
162
|
def update_index_settings(index_name, index_settings)
|
153
|
-
|
163
|
+
http_client.put("#{index_url(index_name)}/_settings", json: index_settings)
|
154
164
|
|
155
165
|
true
|
156
166
|
end
|
@@ -163,7 +173,7 @@ module SearchFlip
|
|
163
173
|
# @return [Hash] The index settings
|
164
174
|
|
165
175
|
def get_index_settings(index_name)
|
166
|
-
|
176
|
+
http_client.headers(accept: "application/json").get("#{index_url(index_name)}/_settings").parse
|
167
177
|
end
|
168
178
|
|
169
179
|
# Sends a refresh request to ElasticSearch. Raises
|
@@ -173,7 +183,7 @@ module SearchFlip
|
|
173
183
|
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
174
184
|
|
175
185
|
def refresh(index_names = nil)
|
176
|
-
|
186
|
+
http_client.post("#{index_names ? index_url(Array(index_names).join(",")) : base_url}/_refresh", json: {})
|
177
187
|
|
178
188
|
true
|
179
189
|
end
|
@@ -188,7 +198,7 @@ module SearchFlip
|
|
188
198
|
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
189
199
|
|
190
200
|
def update_mapping(index_name, type_name, mapping)
|
191
|
-
|
201
|
+
http_client.put("#{type_url(index_name, type_name)}/_mapping", json: mapping)
|
192
202
|
|
193
203
|
true
|
194
204
|
end
|
@@ -201,7 +211,7 @@ module SearchFlip
|
|
201
211
|
# @return [Hash] The current type mapping
|
202
212
|
|
203
213
|
def get_mapping(index_name, type_name)
|
204
|
-
|
214
|
+
http_client.headers(accept: "application/json").get("#{type_url(index_name, type_name)}/_mapping").parse
|
205
215
|
end
|
206
216
|
|
207
217
|
# Deletes the specified index from ElasticSearch. Raises
|
@@ -211,7 +221,7 @@ module SearchFlip
|
|
211
221
|
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
212
222
|
|
213
223
|
def delete_index(index_name)
|
214
|
-
|
224
|
+
http_client.delete index_url(index_name)
|
215
225
|
|
216
226
|
true
|
217
227
|
end
|
@@ -222,7 +232,7 @@ module SearchFlip
|
|
222
232
|
# @return [Boolean] Whether or not the index exists
|
223
233
|
|
224
234
|
def index_exists?(index_name)
|
225
|
-
|
235
|
+
http_client.headers(accept: "application/json").head(index_url(index_name))
|
226
236
|
|
227
237
|
true
|
228
238
|
rescue SearchFlip::ResponseError => e
|
data/lib/search_flip/criteria.rb
CHANGED
@@ -39,18 +39,18 @@ module SearchFlip
|
|
39
39
|
|
40
40
|
fresh.tap do |criteria|
|
41
41
|
criteria.profile_value = other.profile_value unless other.profile_value.nil?
|
42
|
-
criteria.
|
43
|
-
criteria.
|
44
|
-
criteria.
|
45
|
-
criteria.suggest_values = (criteria.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
|
42
|
+
criteria.failsafe_value = other.failsafe_value unless other.failsafe_value.nil?
|
43
|
+
criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
|
44
|
+
criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
|
46
45
|
criteria.offset_value = other.offset_value if other.offset_value
|
47
46
|
criteria.limit_value = other.limit_value if other.limit_value
|
47
|
+
criteria.scroll_args = other.scroll_args if other.scroll_args
|
48
|
+
|
49
|
+
criteria.source_value = (criteria.source_value || []) + other.source_value if other.source_value
|
50
|
+
criteria.sort_values = (criteria.sort_values || []) + other.sort_values if other.sort_values
|
48
51
|
criteria.includes_values = (criteria.includes_values || []) + other.includes_values if other.includes_values
|
49
52
|
criteria.preload_values = (criteria.preload_values || []) + other.preload_values if other.preload_values
|
50
53
|
criteria.eager_load_values = (criteria.eager_load_values || []) + other.eager_load_values if other.eager_load_values
|
51
|
-
criteria.failsafe_value = other.failsafe_value unless other.failsafe_value.nil?
|
52
|
-
criteria.scroll_args = other.scroll_args if other.scroll_args
|
53
|
-
criteria.custom_value = (criteria.custom_value || {}).merge(other.custom_value) if other.custom_value
|
54
54
|
criteria.search_values = (criteria.search_values || []) + other.search_values if other.search_values
|
55
55
|
criteria.must_values = (criteria.must_values || []) + other.must_values if other.must_values
|
56
56
|
criteria.must_not_values = (criteria.must_not_values || []) + other.must_not_values if other.must_not_values
|
@@ -61,9 +61,11 @@ module SearchFlip
|
|
61
61
|
criteria.post_must_not_values = (criteria.post_must_not_values || []) + other.post_must_not_values if other.post_must_not_values
|
62
62
|
criteria.post_should_values = (criteria.post_should_values || []) + other.post_should_values if other.post_should_values
|
63
63
|
criteria.post_filter_values = (criteria.post_filter_values || []) + other.post_filter_values if other.post_filter_values
|
64
|
+
|
65
|
+
criteria.highlight_values = (criteria.highlight_values || {}).merge(other.highlight_values) if other.highlight_values
|
66
|
+
criteria.suggest_values = (criteria.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
|
67
|
+
criteria.custom_value = (criteria.custom_value || {}).merge(other.custom_value) if other.custom_value
|
64
68
|
criteria.aggregation_values = (criteria.aggregation_values || {}).merge(other.aggregation_values) if other.aggregation_values
|
65
|
-
criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
|
66
|
-
criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
@@ -175,7 +177,7 @@ module SearchFlip
|
|
175
177
|
res = {}
|
176
178
|
|
177
179
|
if must_values || search_values || must_not_values || should_values || filter_values
|
178
|
-
if
|
180
|
+
if connection.version.to_i >= 2
|
179
181
|
res[:query] = {
|
180
182
|
bool: {}
|
181
183
|
.merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {})
|
@@ -213,7 +215,7 @@ module SearchFlip
|
|
213
215
|
res[:aggregations] = aggregation_values if aggregation_values
|
214
216
|
|
215
217
|
if post_must_values || post_search_values || post_must_not_values || post_should_values || post_filter_values
|
216
|
-
if
|
218
|
+
if connection.version.to_i >= 2
|
217
219
|
res[:post_filter] = {
|
218
220
|
bool: {}
|
219
221
|
.merge(post_must_values || post_search_values ? { must: (post_must_values || []) + (post_search_values || []) } : {})
|
@@ -357,10 +359,10 @@ module SearchFlip
|
|
357
359
|
dupped_request.delete(:from)
|
358
360
|
dupped_request.delete(:size)
|
359
361
|
|
360
|
-
if
|
361
|
-
|
362
|
+
if connection.version.to_i >= 5
|
363
|
+
connection.http_client.post("#{target.type_url}/_delete_by_query", json: dupped_request)
|
362
364
|
else
|
363
|
-
|
365
|
+
connection.http_client.delete("#{target.type_url}/_query", json: dupped_request)
|
364
366
|
end
|
365
367
|
|
366
368
|
target.refresh if SearchFlip::Config[:auto_refresh]
|
@@ -673,6 +675,32 @@ module SearchFlip
|
|
673
675
|
|
674
676
|
alias_method :each, :find_each
|
675
677
|
|
678
|
+
# Fetches the results specified by the criteria in batches using the
|
679
|
+
# ElasticSearch scroll API and yields each result. The batch size and scroll
|
680
|
+
# API timeout can be specified. Checkout out the ElasticSearch docs for
|
681
|
+
# further details.
|
682
|
+
#
|
683
|
+
# @example
|
684
|
+
# CommentIndex.search("hello world").find_each_result(batch_size: 100) do |result|
|
685
|
+
# # ...
|
686
|
+
# end
|
687
|
+
#
|
688
|
+
# @param options [Hash] The options to control the fetching of batches
|
689
|
+
# @option options batch_size [Fixnum] The number of records to fetch per
|
690
|
+
# batch. Uses #limit to control the batch size.
|
691
|
+
# @option options timeout [String] The timeout per scroll request, ie how
|
692
|
+
# long ElasticSearch will keep the request handle open.
|
693
|
+
|
694
|
+
def find_each_result(options = {})
|
695
|
+
return enum_for(:find_each_result, options) unless block_given?
|
696
|
+
|
697
|
+
find_results_in_batches options do |batch|
|
698
|
+
batch.each do |result|
|
699
|
+
yield result
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
676
704
|
# Executes the search request for the current criteria, ie sends the
|
677
705
|
# request to ElasticSearch and returns the response. Connection and
|
678
706
|
# response errors will be rescued if you specify the criteria to be
|
@@ -685,19 +713,19 @@ module SearchFlip
|
|
685
713
|
|
686
714
|
def execute
|
687
715
|
@response ||= begin
|
688
|
-
http_request =
|
716
|
+
http_request = connection.http_client.headers(accept: "application/json")
|
689
717
|
|
690
718
|
http_response =
|
691
719
|
if scroll_args && scroll_args[:id]
|
692
|
-
if
|
720
|
+
if connection.version.to_i >= 2
|
693
721
|
http_request.post(
|
694
|
-
"#{
|
722
|
+
"#{connection.base_url}/_search/scroll",
|
695
723
|
json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] }
|
696
724
|
)
|
697
725
|
else
|
698
726
|
http_request
|
699
727
|
.headers(content_type: "text/plain")
|
700
|
-
.post("#{
|
728
|
+
.post("#{connection.base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
|
701
729
|
end
|
702
730
|
elsif scroll_args
|
703
731
|
http_request.post(
|
@@ -776,6 +804,8 @@ module SearchFlip
|
|
776
804
|
:hits, :ids, :count, :size, :length, :took, :aggregations, :suggestions,
|
777
805
|
:scope, :results, :records, :scroll_id, :raw_response
|
778
806
|
|
807
|
+
def_delegators :target, :connection
|
808
|
+
|
779
809
|
private
|
780
810
|
|
781
811
|
def yield_in_batches(options = {})
|
@@ -7,42 +7,43 @@ module SearchFlip
|
|
7
7
|
# with ElasticSearch.
|
8
8
|
|
9
9
|
class HTTPClient
|
10
|
-
|
11
|
-
attr_accessor :headers_hash
|
10
|
+
attr_accessor :request
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
[:get, :post, :put, :delete, :head].each do |method|
|
20
|
-
define_method method do |*args|
|
21
|
-
execute(method, *args)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
12
|
+
def initialize
|
13
|
+
self.request = HTTP
|
14
|
+
end
|
26
15
|
|
27
|
-
|
28
|
-
|
16
|
+
class << self
|
17
|
+
extend Forwardable
|
29
18
|
|
30
|
-
|
19
|
+
def_delegators :new, :headers, :via, :basic_auth, :auth
|
20
|
+
def_delegators :new, :get, :post, :put, :delete, :head
|
21
|
+
end
|
31
22
|
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
[:headers, :via, :basic_auth, :auth].each do |method|
|
24
|
+
define_method method do |*args|
|
25
|
+
dup.tap do |client|
|
26
|
+
client.request = request.send(method, *args)
|
27
|
+
end
|
35
28
|
end
|
36
29
|
end
|
37
30
|
|
38
|
-
|
39
|
-
|
31
|
+
[:get, :post, :put, :delete, :head].each do |method|
|
32
|
+
define_method method do |*args|
|
33
|
+
execute(method, *args)
|
34
|
+
end
|
40
35
|
end
|
41
36
|
|
42
|
-
|
43
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def execute(method, *args)
|
40
|
+
response = request.send(method, *args)
|
41
|
+
|
42
|
+
raise SearchFlip::ResponseError.new(code: response.code, body: response.body.to_s) unless response.status.success?
|
44
43
|
|
45
|
-
|
44
|
+
response
|
45
|
+
rescue HTTP::ConnectionError => e
|
46
|
+
raise SearchFlip::ConnectionError, e.message
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
data/lib/search_flip/index.rb
CHANGED
@@ -247,8 +247,8 @@ module SearchFlip
|
|
247
247
|
:post_filter, :post_must, :post_must_not, :post_should, :aggregate, :scroll, :source,
|
248
248
|
:includes, :eager_load, :preload, :sort, :resort, :order, :reorder, :offset, :limit, :paginate,
|
249
249
|
:page, :per, :search, :highlight, :suggest, :custom, :find_in_batches, :find_results_in_batches,
|
250
|
-
:find_each, :failsafe, :total_entries, :total_count, :timeout, :terminate_after,
|
251
|
-
:should, :should_not, :must, :must_not
|
250
|
+
:find_each, :find_each_result, :failsafe, :total_entries, :total_count, :timeout, :terminate_after,
|
251
|
+
:records, :results, :should, :should_not, :must, :must_not
|
252
252
|
|
253
253
|
# Override to specify the type name used within ElasticSearch. Recap,
|
254
254
|
# this gem uses an individual index for each index class, because
|
@@ -396,7 +396,7 @@ module SearchFlip
|
|
396
396
|
# @return [Hash] The specified document
|
397
397
|
|
398
398
|
def get(id, params = {})
|
399
|
-
|
399
|
+
connection.http_client.headers(accept: "application/json").get("#{type_url}/#{id}", params: params).parse
|
400
400
|
end
|
401
401
|
|
402
402
|
# Sends a index refresh request to ElasticSearch. Raises
|
@@ -532,7 +532,9 @@ module SearchFlip
|
|
532
532
|
# raise.
|
533
533
|
|
534
534
|
def bulk(options = {})
|
535
|
-
|
535
|
+
opts = { http_client: connection.http_client }.merge(options)
|
536
|
+
|
537
|
+
SearchFlip::Bulk.new("#{type_url}/_bulk", SearchFlip::Config[:bulk_limit], opts) do |indexer|
|
536
538
|
yield indexer
|
537
539
|
end
|
538
540
|
|
data/lib/search_flip/response.rb
CHANGED
@@ -167,7 +167,15 @@ module SearchFlip
|
|
167
167
|
# @return [Array] An array of results
|
168
168
|
|
169
169
|
def results
|
170
|
-
@results ||= hits["hits"].map
|
170
|
+
@results ||= hits["hits"].map do |hit|
|
171
|
+
raw_result = hit["_source"]
|
172
|
+
|
173
|
+
raw_result["_hit"] = hit.each_with_object({}) do |(key, value), hash|
|
174
|
+
hash[key] = value if key != "_source"
|
175
|
+
end
|
176
|
+
|
177
|
+
Result.new(raw_result)
|
178
|
+
end
|
171
179
|
end
|
172
180
|
|
173
181
|
# Returns the named sugggetion, if a name is specified or alle suggestions.
|
data/lib/search_flip/version.rb
CHANGED
data/search_flip.gemspec
CHANGED
@@ -19,12 +19,17 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
+
spec.post_install_message = <<~MESSAGE
|
23
|
+
Thanks for using search_flip!
|
24
|
+
When upgrading from 1.x to 2.x, please check out
|
25
|
+
https://github.com/mrkamel/search_flip/blob/master/UPDATING.md
|
26
|
+
MESSAGE
|
27
|
+
|
22
28
|
spec.add_development_dependency "activerecord", ">= 3.0"
|
23
29
|
spec.add_development_dependency "bundler"
|
24
30
|
spec.add_development_dependency "factory_bot"
|
25
|
-
spec.add_development_dependency "minitest"
|
26
|
-
spec.add_development_dependency "mocha"
|
27
31
|
spec.add_development_dependency "rake"
|
32
|
+
spec.add_development_dependency "rspec"
|
28
33
|
spec.add_development_dependency "sqlite3", "~> 1.3.6"
|
29
34
|
spec.add_development_dependency "timecop"
|
30
35
|
spec.add_development_dependency "webmock"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
RSpec::Matchers.define :delegate do |method|
|
3
|
+
match do |delegator|
|
4
|
+
@method = method
|
5
|
+
@delegator = delegator
|
6
|
+
|
7
|
+
return false unless @delegator.respond_to?(@to)
|
8
|
+
return false unless @delegator.respond_to?(@method)
|
9
|
+
|
10
|
+
target = double
|
11
|
+
|
12
|
+
allow(@delegator).to receive(@to).and_return(target)
|
13
|
+
allow(target).to receive(@method).and_return(:called)
|
14
|
+
|
15
|
+
@delegator.send(@method) == :called
|
16
|
+
end
|
17
|
+
|
18
|
+
description do
|
19
|
+
"delegate :#{@method} to :#{@to}"
|
20
|
+
end
|
21
|
+
|
22
|
+
failure_message do
|
23
|
+
"expected #{@delegator} to delegate :#{@method} to :#{@to}"
|
24
|
+
end
|
25
|
+
|
26
|
+
failure_message_when_negated do
|
27
|
+
"expected #{@delegator} not to delegate :#{@method} to :#{@to}"
|
28
|
+
end
|
29
|
+
|
30
|
+
chain(:to) { |to| @to = to }
|
31
|
+
end
|
32
|
+
|