search_flip 2.0.0.beta2 → 2.0.0.beta3
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/.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
|
+
|