search_flip 2.0.0.beta → 2.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -6
- data/README.md +39 -0
- data/UPDATING.md +113 -0
- data/lib/search_flip/connection.rb +125 -0
- data/lib/search_flip/criteria.rb +22 -9
- data/lib/search_flip/index.rb +50 -32
- data/lib/search_flip/version.rb +1 -1
- data/test/search_flip/connection_test.rb +91 -0
- data/test/search_flip/criteria_test.rb +7 -9
- data/test/search_flip/index_test.rb +112 -43
- data/test/test_helper.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61c625b2c60157b40c9508e6847e9727b1a468e03910afe317f39fd9687310bd
|
4
|
+
data.tar.gz: bdfc1613945464bb559243cf3d98fe9d29308d35ab2c6133db065bd9efa70322
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24dbb5c4294827bd66b24d67a873adfb819eba35d74c393149afe5133f6b59339254e2d3348130035675b0e2ce40cdc223133db0ed52bd2e9ca34d87e9383992
|
7
|
+
data.tar.gz: 8066d64b3695d56fff2f4445602f7d4a86a815a536e825ed7a5287c5738193dfc2e4e8a81d6ea95c03e945cea564a7ff70be43c9fb97e3c30d96c972703ab57f
|
data/CHANGELOG.md
CHANGED
@@ -3,15 +3,16 @@
|
|
3
3
|
|
4
4
|
## v2.0.0
|
5
5
|
|
6
|
-
* **BREAKING**: Migration steps
|
7
|
-
* Change `SearchFlip.version` to `SearchFlip::Connection#version`
|
8
|
-
* Change `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
|
9
|
-
* Change `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
|
10
|
-
* Change `SearchFlip::Criteria#execute(base_url: '...')` to `SearchFlip::Criteria#execute(connection: SearchFlip::Connection.new(base_url: '...'))`
|
11
6
|
* Added `SearchFlip::Connection`
|
12
|
-
*
|
7
|
+
* [BREAKING] Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
|
8
|
+
* [BREAKING] Changed `SearchFlip.version` to `SearchFlip::Connection#version`
|
9
|
+
* [BREAKING] Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
|
10
|
+
* [BREAKING] Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
|
11
|
+
* [BREAKING] Removed `base_url` param from `SearchFlip::Critiera#execute`
|
13
12
|
* Added `SearchFlip::Connection#get_aliases`
|
13
|
+
* Added `SearchFlip::Connection#get_indices`
|
14
14
|
* Added `SearchFlip::Connection#alias_exists?`
|
15
|
+
* Added `SearchFlip::Index#with_settings` and `SearchFlip::Criteria#with_settings`
|
15
16
|
|
16
17
|
## v1.1.0
|
17
18
|
|
data/README.md
CHANGED
@@ -22,6 +22,10 @@ end
|
|
22
22
|
CommentIndex.range(:created_at, gt: Date.today - 1.week, lt: Date.today).where(state: ["approved", "pending"])
|
23
23
|
```
|
24
24
|
|
25
|
+
## Updating from previous SearchFlip versions
|
26
|
+
|
27
|
+
Checkout [UPDATING.md](./UPDATING.md) for detailed instructions.
|
28
|
+
|
25
29
|
## Comparison with other gems
|
26
30
|
|
27
31
|
There are great ruby gems to work with Elasticsearch like e.g. searchkick and
|
@@ -250,6 +254,41 @@ CommentIndex.match_all.find_each do |record|
|
|
250
254
|
end
|
251
255
|
```
|
252
256
|
|
257
|
+
## Working with Elasticsearch Aliases
|
258
|
+
|
259
|
+
You can use and manage Elasticsearch Aliases like the following:
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
class UserIndex
|
263
|
+
include SearchFlip::Index
|
264
|
+
|
265
|
+
def self.index_name
|
266
|
+
alias_name
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.alias_name
|
270
|
+
"users"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
Then, create an index, import the records and add the alias like:
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
new_user_index = UserIndex.with_settings(index_name: "users-#{SecureRandom.hex}")
|
279
|
+
new_user_index.create_index
|
280
|
+
new_user_index.import User.all
|
281
|
+
new_user.connection.update_aliases(actions: [
|
282
|
+
add: { index: new_user_index.index_name, alias: new_user_index.alias_name }
|
283
|
+
])
|
284
|
+
```
|
285
|
+
|
286
|
+
If the alias already exists, you of course have to remove it as well first
|
287
|
+
within `update_aliases`.
|
288
|
+
|
289
|
+
Please note that `with_settings(index_name: '...')` returns an anonymous, i.e.
|
290
|
+
temporary, class inherting from UserIndex and overwriting `index_name`.
|
291
|
+
|
253
292
|
## Advanced Usage
|
254
293
|
|
255
294
|
SearchFlip supports even more advanced usages, like e.g. post filters, filtered
|
data/UPDATING.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
# Updating from previous SearchFlip versions
|
3
|
+
|
4
|
+
## Update 1.x to 2.x
|
5
|
+
|
6
|
+
* [BREAKING] Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
|
7
|
+
|
8
|
+
1.x:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
class MyIndex
|
12
|
+
include SearchFlip::Index
|
13
|
+
|
14
|
+
# ...
|
15
|
+
|
16
|
+
def self.base_url
|
17
|
+
"..."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
2.x:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class MyIndex
|
26
|
+
include SearchFlip::Index
|
27
|
+
|
28
|
+
# ...
|
29
|
+
|
30
|
+
def self connection
|
31
|
+
@connection ||= SearchFlip::Connection.new(base_url: "...")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
* [BREAKING] Changed `SearchFlip.version` to `SearchFlip::Connection#version`
|
37
|
+
|
38
|
+
1.x:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
SearchFlip.version
|
42
|
+
```
|
43
|
+
|
44
|
+
2.x:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
MyIndex.connection.version
|
48
|
+
|
49
|
+
# or
|
50
|
+
|
51
|
+
connection = SearchFlip::Connection.new(base_url: "...")
|
52
|
+
connection.version
|
53
|
+
```
|
54
|
+
|
55
|
+
* [BREAKING] Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
|
56
|
+
|
57
|
+
1.x:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
SearchFlip.aliases(actions: [
|
61
|
+
# ...
|
62
|
+
])
|
63
|
+
```
|
64
|
+
|
65
|
+
2.x:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
MyIndex.connection.update_aliases(actions: [
|
69
|
+
# ...
|
70
|
+
])
|
71
|
+
|
72
|
+
# or
|
73
|
+
|
74
|
+
connection = SearchFlip::Connection.new(base_url: "...")
|
75
|
+
connection.update_aliases(actions: [
|
76
|
+
# ...
|
77
|
+
])
|
78
|
+
```
|
79
|
+
|
80
|
+
* [BREAKING] Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
|
81
|
+
|
82
|
+
1.x:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
SearchFlip.msearch(queries)
|
86
|
+
```
|
87
|
+
|
88
|
+
2.x:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
MyIndex.connection.msearch(queries)
|
92
|
+
|
93
|
+
# or
|
94
|
+
|
95
|
+
connection = SearchFlip::Connection.new(base_url: "...")
|
96
|
+
connection.msearch(queries)
|
97
|
+
```
|
98
|
+
|
99
|
+
* [BREAKING] Removed `base_url` param from `SearchFlip::Critiera#execute`
|
100
|
+
|
101
|
+
1.x:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
MyIndex.where(id: 1).execute(base_url: "...")
|
105
|
+
```
|
106
|
+
|
107
|
+
2.x:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
connection = SearchFlip::Connection.new(base_url: "...")
|
111
|
+
MyIndex.where(id: 1).with_settings(connection: connection).execute
|
112
|
+
```
|
113
|
+
|
@@ -126,6 +126,131 @@ module SearchFlip
|
|
126
126
|
.get("#{base_url}/_cat/indices/#{name}")
|
127
127
|
.parse
|
128
128
|
end
|
129
|
+
|
130
|
+
# Creates the specified index within ElasticSearch and applies index
|
131
|
+
# settings, if specified. Raises SearchFlip::ResponseError in case any
|
132
|
+
# errors occur.
|
133
|
+
#
|
134
|
+
# @param index_name [String] The index name
|
135
|
+
# @param index_settings [Hash] The index settings
|
136
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
137
|
+
|
138
|
+
def create_index(index_name, index_settings = {})
|
139
|
+
SearchFlip::HTTPClient.put(index_url(index_name), json: index_settings)
|
140
|
+
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
# Updates the index settings within ElasticSearch according to the index
|
145
|
+
# settings specified. Raises SearchFlip::ResponseError in case any
|
146
|
+
# errors occur.
|
147
|
+
#
|
148
|
+
# @param index_name [String] The index name to update the settings for
|
149
|
+
# @param index_settings [Hash] The index settings
|
150
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
151
|
+
|
152
|
+
def update_index_settings(index_name, index_settings)
|
153
|
+
SearchFlip::HTTPClient.put("#{index_url(index_name)}/_settings", json: index_settings)
|
154
|
+
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
158
|
+
# Fetches the index settings for the specified index from ElasticSearch.
|
159
|
+
# Sends a GET request to index_url/_settings. Raises
|
160
|
+
# SearchFlip::ResponseError in case any errors occur.
|
161
|
+
#
|
162
|
+
# @param index_name [String] The index name
|
163
|
+
# @return [Hash] The index settings
|
164
|
+
|
165
|
+
def get_index_settings(index_name)
|
166
|
+
SearchFlip::HTTPClient.headers(accept: "application/json").get("#{index_url(index_name)}/_settings").parse
|
167
|
+
end
|
168
|
+
|
169
|
+
# Sends a refresh request to ElasticSearch. Raises
|
170
|
+
# SearchFlip::ResponseError in case any errors occur.
|
171
|
+
#
|
172
|
+
# @param index_names [String, Array] The optional index names to refresh
|
173
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
174
|
+
|
175
|
+
def refresh(index_names = nil)
|
176
|
+
SearchFlip::HTTPClient.post("#{index_names ? index_url(Array(index_names).join(",")) : base_url}/_refresh", json: {})
|
177
|
+
|
178
|
+
true
|
179
|
+
end
|
180
|
+
|
181
|
+
# Updates the type mapping for the specified index and type within
|
182
|
+
# ElasticSearch according to the specified mapping. Raises
|
183
|
+
# SearchFlip::ResponseError in case any errors occur.
|
184
|
+
#
|
185
|
+
# @param index_name [String] The index name
|
186
|
+
# @param type_name [String] The type name
|
187
|
+
# @param mapping [Hash] The mapping
|
188
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
189
|
+
|
190
|
+
def update_mapping(index_name, type_name, mapping)
|
191
|
+
SearchFlip::HTTPClient.put("#{type_url(index_name, type_name)}/_mapping", json: mapping)
|
192
|
+
|
193
|
+
true
|
194
|
+
end
|
195
|
+
|
196
|
+
# Retrieves the mapping for the specified index and type from
|
197
|
+
# ElasticSearch. Raises SearchFlip::ResponseError in case any errors occur.
|
198
|
+
#
|
199
|
+
# @param index_name [String] The index name
|
200
|
+
# @param type_name [String] The type name
|
201
|
+
# @return [Hash] The current type mapping
|
202
|
+
|
203
|
+
def get_mapping(index_name, type_name)
|
204
|
+
SearchFlip::HTTPClient.headers(accept: "application/json").get("#{type_url(index_name, type_name)}/_mapping").parse
|
205
|
+
end
|
206
|
+
|
207
|
+
# Deletes the specified index from ElasticSearch. Raises
|
208
|
+
# SearchFlip::ResponseError in case any errors occur.
|
209
|
+
#
|
210
|
+
# @param index_name [String] The index name
|
211
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
212
|
+
|
213
|
+
def delete_index(index_name)
|
214
|
+
SearchFlip::HTTPClient.delete index_url(index_name)
|
215
|
+
|
216
|
+
true
|
217
|
+
end
|
218
|
+
|
219
|
+
# Returns whether or not the specified index already exists.
|
220
|
+
#
|
221
|
+
# @param index_name [String] The index name
|
222
|
+
# @return [Boolean] Whether or not the index exists
|
223
|
+
|
224
|
+
def index_exists?(index_name)
|
225
|
+
SearchFlip::HTTPClient.headers(accept: "application/json").head(index_url(index_name))
|
226
|
+
|
227
|
+
true
|
228
|
+
rescue SearchFlip::ResponseError => e
|
229
|
+
return false if e.code == 404
|
230
|
+
|
231
|
+
raise e
|
232
|
+
end
|
233
|
+
|
234
|
+
# Returns the full ElasticSearch type URL, ie base URL, index name with
|
235
|
+
# prefix and type name.
|
236
|
+
#
|
237
|
+
# @param index_name [String] The index name
|
238
|
+
# @param type_name [String] The type name
|
239
|
+
# @return [String] The ElasticSearch type URL
|
240
|
+
|
241
|
+
def type_url(index_name, type_name)
|
242
|
+
"#{index_url(index_name)}/#{type_name}"
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns the ElasticSearch index URL for the specified index name, ie base
|
246
|
+
# URL and index name with prefix.
|
247
|
+
#
|
248
|
+
# @param index_name [String] The index name
|
249
|
+
# @return [String] The ElasticSearch index URL
|
250
|
+
|
251
|
+
def index_url(index_name)
|
252
|
+
"#{base_url}/#{index_name}"
|
253
|
+
end
|
129
254
|
end
|
130
255
|
end
|
131
256
|
|
data/lib/search_flip/criteria.rb
CHANGED
@@ -60,7 +60,7 @@ module SearchFlip
|
|
60
60
|
criteria.post_must_values = (criteria.post_must_values || []) + other.post_must_values if other.post_must_values
|
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
|
-
criteria.post_filter_values = (criteria.
|
63
|
+
criteria.post_filter_values = (criteria.post_filter_values || []) + other.post_filter_values if other.post_filter_values
|
64
64
|
criteria.aggregation_values = (criteria.aggregation_values || {}).merge(other.aggregation_values) if other.aggregation_values
|
65
65
|
criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
|
66
66
|
criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
|
@@ -149,6 +149,22 @@ module SearchFlip
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
+
# Allows to set query specific settings like e.g. connection and index
|
153
|
+
# name. Please note, however, that this should only be used for special
|
154
|
+
# cases and the subsequent query can not be serialized. Checkout
|
155
|
+
# SearchFlip::Index.with_settings for more details.
|
156
|
+
#
|
157
|
+
# @example
|
158
|
+
# UserIndex.where("...").with_settings(connection: ProxyConnection)
|
159
|
+
#
|
160
|
+
# @return [SearchFlip::Criteria] Simply returns self
|
161
|
+
|
162
|
+
def with_settings(*args)
|
163
|
+
fresh.tap do |criteria|
|
164
|
+
criteria.target = target.with_settings(*args)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
152
168
|
# Generates the request object from the attributes specified via chaining,
|
153
169
|
# like eg offset, limit, query, filters, aggregations, etc and returns a
|
154
170
|
# Hash that later gets serialized as JSON.
|
@@ -662,15 +678,12 @@ module SearchFlip
|
|
662
678
|
# response errors will be rescued if you specify the criteria to be
|
663
679
|
# #failsafe, such that an empty response is returned instead.
|
664
680
|
#
|
665
|
-
# @param connection An optional alternative connection to used to send the
|
666
|
-
# request to for e.g. proxying
|
667
|
-
#
|
668
681
|
# @example
|
669
682
|
# response = CommentIndex.search("hello world").execute
|
670
683
|
#
|
671
684
|
# @return [SearchFlip::Response] The response object
|
672
685
|
|
673
|
-
def execute
|
686
|
+
def execute
|
674
687
|
@response ||= begin
|
675
688
|
http_request = SearchFlip::HTTPClient.headers(accept: "application/json")
|
676
689
|
|
@@ -678,22 +691,22 @@ module SearchFlip
|
|
678
691
|
if scroll_args && scroll_args[:id]
|
679
692
|
if target.connection.version.to_i >= 2
|
680
693
|
http_request.post(
|
681
|
-
"#{connection.base_url}/_search/scroll",
|
694
|
+
"#{target.connection.base_url}/_search/scroll",
|
682
695
|
json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] }
|
683
696
|
)
|
684
697
|
else
|
685
698
|
http_request
|
686
699
|
.headers(content_type: "text/plain")
|
687
|
-
.post("#{connection.base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
|
700
|
+
.post("#{target.connection.base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
|
688
701
|
end
|
689
702
|
elsif scroll_args
|
690
703
|
http_request.post(
|
691
|
-
"#{target.type_url
|
704
|
+
"#{target.type_url}/_search",
|
692
705
|
params: { scroll: scroll_args[:timeout] },
|
693
706
|
json: request
|
694
707
|
)
|
695
708
|
else
|
696
|
-
http_request.post("#{target.type_url
|
709
|
+
http_request.post("#{target.type_url}/_search", json: request)
|
697
710
|
end
|
698
711
|
|
699
712
|
SearchFlip::Response.new(self, http_response.parse)
|
data/lib/search_flip/index.rb
CHANGED
@@ -68,6 +68,34 @@ module SearchFlip
|
|
68
68
|
{}
|
69
69
|
end
|
70
70
|
|
71
|
+
# Creates an anonymous class inheriting from the current index with a
|
72
|
+
# custom index name and/or connection. This is e.g. useful when working
|
73
|
+
# with aliases or proxies.
|
74
|
+
#
|
75
|
+
# @example Basic usage
|
76
|
+
# UserIndex.with_settings(index_name: 'new_user_index')
|
77
|
+
# # => #<Class:0x...>
|
78
|
+
#
|
79
|
+
# @example Working with aliases
|
80
|
+
# new_index = UserIndex.with_settings(index_name: 'new_user_index')
|
81
|
+
# new_index.create_index
|
82
|
+
# new_index.import User.all
|
83
|
+
# new_index.connection.update_aliases("...")
|
84
|
+
#
|
85
|
+
# @example Working with proxies
|
86
|
+
# query = UserIndex.with_settings(connection: ProxyConnection).where("...")
|
87
|
+
#
|
88
|
+
# @param index_name [String] A custom index_name
|
89
|
+
# @param connection [SearchFlip::Connection] A custom connection
|
90
|
+
# @return [Class] An anonymous class
|
91
|
+
|
92
|
+
def with_settings(index_name: nil, connection: nil)
|
93
|
+
Class.new(self).tap do |klass|
|
94
|
+
klass.define_singleton_method(:index_name) { index_name } if index_name
|
95
|
+
klass.define_singleton_method(:connection) { connection } if connection
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
71
99
|
# @abstract
|
72
100
|
#
|
73
101
|
# Override this method to generate a hash representation of a record,
|
@@ -278,13 +306,7 @@ module SearchFlip
|
|
278
306
|
# @return [Boolean] Whether or not the index exists
|
279
307
|
|
280
308
|
def index_exists?
|
281
|
-
|
282
|
-
|
283
|
-
true
|
284
|
-
rescue SearchFlip::ResponseError => e
|
285
|
-
return false if e.code == 404
|
286
|
-
|
287
|
-
raise e
|
309
|
+
connection.index_exists?(index_name_with_prefix)
|
288
310
|
end
|
289
311
|
|
290
312
|
# Fetches the index settings from ElasticSearch. Sends a GET request to
|
@@ -294,36 +316,38 @@ module SearchFlip
|
|
294
316
|
# @return [Hash] The index settings
|
295
317
|
|
296
318
|
def get_index_settings
|
297
|
-
|
319
|
+
connection.get_index_settings(index_name_with_prefix)
|
298
320
|
end
|
299
321
|
|
300
322
|
# Creates the index within ElasticSearch and applies index settings, if
|
301
323
|
# specified. Raises SearchFlip::ResponseError in case any errors
|
302
324
|
# occur.
|
325
|
+
#
|
326
|
+
# @param include_mapping [Boolean] Whether or not to include the mapping
|
327
|
+
# @return [Boolean] Returns true or false
|
303
328
|
|
304
|
-
def create_index
|
305
|
-
|
329
|
+
def create_index(include_mapping: false)
|
330
|
+
json = index_settings
|
331
|
+
json = json.merge(mappings: mapping) if include_mapping
|
306
332
|
|
307
|
-
|
333
|
+
connection.create_index(index_name_with_prefix, json)
|
308
334
|
end
|
309
335
|
|
310
336
|
# Updates the index settings within ElasticSearch according to the index
|
311
337
|
# settings specified. Raises SearchFlip::ResponseError in case any
|
312
338
|
# errors occur.
|
339
|
+
#
|
340
|
+
# @return [Boolean] Returns true or false
|
313
341
|
|
314
342
|
def update_index_settings
|
315
|
-
|
316
|
-
|
317
|
-
true
|
343
|
+
connection.update_index_settings(index_name_with_prefix, index_settings)
|
318
344
|
end
|
319
345
|
|
320
346
|
# Deletes the index from ElasticSearch. Raises SearchFlip::ResponseError
|
321
347
|
# in case any errors occur.
|
322
348
|
|
323
349
|
def delete_index
|
324
|
-
|
325
|
-
|
326
|
-
true
|
350
|
+
connection.delete_index(index_name_with_prefix)
|
327
351
|
end
|
328
352
|
|
329
353
|
# Specifies a type mapping. Override to specify a custom mapping.
|
@@ -351,9 +375,7 @@ module SearchFlip
|
|
351
375
|
# errors occur.
|
352
376
|
|
353
377
|
def update_mapping
|
354
|
-
|
355
|
-
|
356
|
-
true
|
378
|
+
connection.update_mapping(index_name_with_prefix, type_name, mapping)
|
357
379
|
end
|
358
380
|
|
359
381
|
# Retrieves the current type mapping from ElasticSearch. Raises
|
@@ -362,13 +384,15 @@ module SearchFlip
|
|
362
384
|
# @return [Hash] The current type mapping
|
363
385
|
|
364
386
|
def get_mapping
|
365
|
-
|
387
|
+
connection.get_mapping(index_name_with_prefix, type_name)
|
366
388
|
end
|
367
389
|
|
368
390
|
# Retrieves the document specified by id from ElasticSearch. Raises
|
369
391
|
# SearchFlip::ResponseError specific exceptions in case any errors
|
370
392
|
# occur.
|
371
393
|
#
|
394
|
+
# @param id [String, Fixnum] The id to get
|
395
|
+
# @param params [Hash] Optional params for the request
|
372
396
|
# @return [Hash] The specified document
|
373
397
|
|
374
398
|
def get(id, params = {})
|
@@ -379,9 +403,7 @@ module SearchFlip
|
|
379
403
|
# SearchFlip::ResponseError in case any errors occur.
|
380
404
|
|
381
405
|
def refresh
|
382
|
-
|
383
|
-
|
384
|
-
true
|
406
|
+
connection.refresh(index_name_with_prefix)
|
385
407
|
end
|
386
408
|
|
387
409
|
# Indexes the given record set, array of records or individual record.
|
@@ -520,23 +542,19 @@ module SearchFlip
|
|
520
542
|
# Returns the full ElasticSearch type URL, ie base URL, index name with
|
521
543
|
# prefix and type name.
|
522
544
|
#
|
523
|
-
# @param connection [SearchFlip::Connection] The connection to use
|
524
|
-
#
|
525
545
|
# @return [String] The ElasticSearch type URL
|
526
546
|
|
527
|
-
def type_url
|
528
|
-
|
547
|
+
def type_url
|
548
|
+
connection.type_url(index_name_with_prefix, type_name)
|
529
549
|
end
|
530
550
|
|
531
551
|
# Returns the ElasticSearch index URL, ie base URL and index name with
|
532
552
|
# prefix.
|
533
553
|
#
|
534
|
-
# @param connection [SearchFlip::Connection] The connection to use
|
535
|
-
#
|
536
554
|
# @return [String] The ElasticSearch index URL
|
537
555
|
|
538
|
-
def index_url
|
539
|
-
|
556
|
+
def index_url
|
557
|
+
connection.index_url(index_name_with_prefix)
|
540
558
|
end
|
541
559
|
|
542
560
|
# Returns the SearchFlip::Connection for the index.
|
data/lib/search_flip/version.rb
CHANGED
@@ -66,5 +66,96 @@ class SearchFlip::ConnectionTest < SearchFlip::TestCase
|
|
66
66
|
assert_equal connection.get_indices.map { |index| index["index"] }.sort, ["comments", "products"]
|
67
67
|
assert_equal connection.get_indices("com*").map { |index| index["index"] }.sort, ["comments"]
|
68
68
|
end
|
69
|
+
|
70
|
+
def test_create_index
|
71
|
+
connection = SearchFlip::Connection.new
|
72
|
+
|
73
|
+
assert connection.create_index("index_name")
|
74
|
+
assert connection.index_exists?("index_name")
|
75
|
+
ensure
|
76
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_create_index_with_index_payload
|
80
|
+
connection = SearchFlip::Connection.new
|
81
|
+
|
82
|
+
connection.create_index("index_name", settings: { number_of_shards: 3 })
|
83
|
+
|
84
|
+
assert_equal connection.get_index_settings("index_name")["index_name"]["settings"]["index"]["number_of_shards"], "3"
|
85
|
+
ensure
|
86
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_update_index_settings
|
90
|
+
connection = SearchFlip::Connection.new
|
91
|
+
|
92
|
+
connection.create_index("index_name")
|
93
|
+
connection.update_index_settings("index_name", settings: { number_of_replicas: 3 })
|
94
|
+
|
95
|
+
assert_equal "3", connection.get_index_settings("index_name")["index_name"]["settings"]["index"]["number_of_replicas"]
|
96
|
+
ensure
|
97
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_get_index_settings
|
101
|
+
connection = SearchFlip::Connection.new
|
102
|
+
|
103
|
+
connection.create_index("index_name", settings: { number_of_shards: 3 })
|
104
|
+
|
105
|
+
assert_equal connection.get_index_settings("index_name")["index_name"]["settings"]["index"]["number_of_shards"], "3"
|
106
|
+
ensure
|
107
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_update_mapping
|
111
|
+
connection = SearchFlip::Connection.new
|
112
|
+
|
113
|
+
mapping = { "type_name" => { "properties" => { "id" => { "type" => "long" } } } }
|
114
|
+
|
115
|
+
connection.create_index("index_name")
|
116
|
+
connection.update_mapping("index_name", "type_name", mapping)
|
117
|
+
|
118
|
+
assert_equal connection.get_mapping("index_name", "type_name"), "index_name" => { "mappings" => mapping }
|
119
|
+
ensure
|
120
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_delete_index
|
124
|
+
connection = SearchFlip::Connection.new
|
125
|
+
|
126
|
+
connection.create_index("index_name")
|
127
|
+
assert connection.index_exists?("index_name")
|
128
|
+
|
129
|
+
connection.delete_index("index_name")
|
130
|
+
refute connection.index_exists?("index_name")
|
131
|
+
ensure
|
132
|
+
connection.delete_index("index_name") if connection.index_exists?("index_name")
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_refresh
|
136
|
+
connection = SearchFlip::Connection.new
|
137
|
+
|
138
|
+
connection.create_index("index1")
|
139
|
+
connection.create_index("index2")
|
140
|
+
|
141
|
+
assert connection.refresh
|
142
|
+
assert connection.refresh("index1")
|
143
|
+
assert connection.refresh(["index1", "index2"])
|
144
|
+
ensure
|
145
|
+
connection.delete_index("index1") if connection.index_exists?("index1")
|
146
|
+
connection.delete_index("index2") if connection.index_exists?("index2")
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_index_url
|
150
|
+
connection = SearchFlip::Connection.new(base_url: "base_url")
|
151
|
+
|
152
|
+
assert_equal "base_url/index_name", connection.index_url("index_name")
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_type_url
|
156
|
+
connection = SearchFlip::Connection.new(base_url: "base_url")
|
157
|
+
|
158
|
+
assert_equal "base_url/index_name/type_name", connection.type_url("index_name", "type_name")
|
159
|
+
end
|
69
160
|
end
|
70
161
|
|
@@ -62,6 +62,13 @@ class SearchFlip::CriteriaTest < SearchFlip::TestCase
|
|
62
62
|
refute_includes query2.records, product3
|
63
63
|
end
|
64
64
|
|
65
|
+
def test_with_settings
|
66
|
+
stub_request(:post, "http://127.0.0.1:9200/new_user_index/products/_search")
|
67
|
+
.to_return(status: 200, body: "{}", headers: { content_type: "application/json" })
|
68
|
+
|
69
|
+
ProductIndex.where(id: 1).with_settings(index_name: "new_user_index").execute
|
70
|
+
end
|
71
|
+
|
65
72
|
def test_where_with_array
|
66
73
|
expected1 = create(:product, title: "expected1")
|
67
74
|
expected2 = create(:product, title: "expected2")
|
@@ -211,15 +218,6 @@ class SearchFlip::CriteriaTest < SearchFlip::TestCase
|
|
211
218
|
assert_includes records, expected2
|
212
219
|
end
|
213
220
|
|
214
|
-
def test_execute
|
215
|
-
connection = SearchFlip::Connection.new(base_url: "http://localhost:1234")
|
216
|
-
|
217
|
-
stub_request(:post, "http://localhost:1234/products/products/_search")
|
218
|
-
.to_return(status: 200, body: "{}", headers: { content_type: "application/json" })
|
219
|
-
|
220
|
-
assert_equal ProductIndex.match_all.execute(connection: connection).raw_response, {}
|
221
|
-
end
|
222
|
-
|
223
221
|
def test_exists
|
224
222
|
product1 = create(:product, title: "title1", description: "description1")
|
225
223
|
product2 = create(:product, title: "title2", description: nil)
|
@@ -30,97 +30,166 @@ class SearchFlip::IndexTest < SearchFlip::TestCase
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def test_create_index_works
|
34
34
|
assert TestIndex.create_index
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
ensure
|
36
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
37
|
+
end
|
38
38
|
|
39
|
-
|
39
|
+
def test_create_index_delegates_to_connection
|
40
|
+
TestIndex.connection.expects(:create_index).with("test", {})
|
41
|
+
TestIndex.create_index
|
40
42
|
end
|
41
43
|
|
42
|
-
def
|
44
|
+
def test_create_index_passes_index_settings_to_connection
|
43
45
|
TestIndex.stubs(:index_settings).returns(settings: { number_of_shards: 3 })
|
44
|
-
|
45
46
|
assert TestIndex.create_index
|
46
|
-
assert TestIndex.index_exists?
|
47
47
|
|
48
|
-
|
48
|
+
assert "3", TestIndex.get_index_settings["test"]["settings"]["index"]["number_of_replicas"]
|
49
49
|
ensure
|
50
50
|
TestIndex.delete_index if TestIndex.index_exists?
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
53
|
+
def test_create_index_passes_index_settings_delegates_to_connection
|
54
|
+
TestIndex.stubs(:index_settings).returns(settings: { number_of_shards: 3 })
|
55
|
+
|
56
|
+
TestIndex.connection.expects(:create_index).with("test", settings: { number_of_shards: 3 })
|
57
|
+
TestIndex.create_index
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_create_index_passes_mapping_if_specified
|
61
|
+
TestIndex.stubs(:mapping).returns(test: { properties: { id: { type: "long" } } })
|
54
62
|
assert TestIndex.create_index
|
63
|
+
ensure
|
64
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
65
|
+
end
|
55
66
|
|
56
|
-
|
67
|
+
def test_create_index_passes_mapping_if_specified_delegates_to_connection
|
68
|
+
TestIndex.stubs(:mapping).returns(test: { properties: { id: { type: "long" } } })
|
57
69
|
|
58
|
-
|
70
|
+
TestIndex.connection.expects(:create_index).with("test", mappings: { test: { properties: { id: { type: "long" } } } })
|
71
|
+
TestIndex.create_index(include_mapping: true)
|
72
|
+
end
|
59
73
|
|
60
|
-
|
74
|
+
def test_update_index_settings_works
|
75
|
+
TestIndex.create_index
|
76
|
+
TestIndex.stubs(:index_settings).returns(settings: { number_of_replicas: 3 })
|
77
|
+
TestIndex.update_index_settings
|
61
78
|
ensure
|
62
79
|
TestIndex.delete_index if TestIndex.index_exists?
|
63
80
|
end
|
64
81
|
|
65
|
-
def
|
66
|
-
|
82
|
+
def test_update_index_settings_delegates_to_connection
|
83
|
+
index_settings = { settings: { number_of_replicas: 3 } }
|
84
|
+
|
85
|
+
TestIndex.stubs(:index_settings).returns(settings: { number_of_replicas: 3 })
|
86
|
+
|
87
|
+
TestIndex.connection.expects(:update_index_settings).with("test", index_settings)
|
88
|
+
TestIndex.update_index_settings
|
67
89
|
end
|
68
90
|
|
69
|
-
def
|
70
|
-
|
91
|
+
def test_get_index_settings_works
|
92
|
+
TestIndex.create_index
|
93
|
+
assert TestIndex.get_index_settings
|
94
|
+
ensure
|
95
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
71
96
|
end
|
72
97
|
|
73
|
-
def
|
74
|
-
|
98
|
+
def test_get_index_settings_delegates_to_connection
|
99
|
+
TestIndex.connection.expects(:get_index_settings).with("test")
|
100
|
+
TestIndex.get_index_settings
|
75
101
|
end
|
76
102
|
|
77
|
-
def
|
103
|
+
def test_index_exists_works
|
78
104
|
TestIndex.create_index
|
79
|
-
TestIndex.
|
105
|
+
assert TestIndex.index_exists?
|
106
|
+
ensure
|
107
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
108
|
+
end
|
80
109
|
|
81
|
-
|
110
|
+
def test_index_exists_delegates_to_connection
|
111
|
+
TestIndex.connection.expects(:index_exists?).with("test")
|
112
|
+
TestIndex.index_exists?
|
113
|
+
end
|
82
114
|
|
83
|
-
|
115
|
+
def test_delete_index_works
|
116
|
+
TestIndex.create_index
|
117
|
+
assert TestIndex.delete_index
|
118
|
+
ensure
|
119
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
120
|
+
end
|
84
121
|
|
122
|
+
def test_delete_index_delegates_to_connection
|
123
|
+
TestIndex.connection.expects(:delete_index).with("test")
|
85
124
|
TestIndex.delete_index
|
86
125
|
end
|
87
126
|
|
88
|
-
def
|
89
|
-
|
127
|
+
def test_update_mapping_works
|
128
|
+
TestIndex.stubs(:mapping).returns(test: { properties: { id: { type: "long" } } })
|
129
|
+
|
130
|
+
TestIndex.create_index
|
131
|
+
TestIndex.update_mapping
|
132
|
+
ensure
|
133
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
90
134
|
end
|
91
135
|
|
92
|
-
def
|
93
|
-
|
94
|
-
ProductIndex.import create(:product)
|
136
|
+
def test_update_mapping_delegates_to_connection
|
137
|
+
mapping = { test: { properties: { id: { type: "long" } } } }
|
95
138
|
|
96
|
-
|
97
|
-
|
139
|
+
TestIndex.stubs(:mapping).returns(mapping)
|
140
|
+
|
141
|
+
TestIndex.connection.expects(:update_mapping).with("test", "test", mapping)
|
142
|
+
TestIndex.update_mapping
|
98
143
|
end
|
99
144
|
|
100
|
-
def
|
101
|
-
|
145
|
+
def test_get_mapping_works
|
146
|
+
TestIndex.create_index
|
147
|
+
TestIndex.update_mapping
|
102
148
|
|
103
|
-
|
149
|
+
assert TestIndex.get_mapping
|
150
|
+
ensure
|
151
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
152
|
+
end
|
104
153
|
|
105
|
-
|
154
|
+
def test_get_mapping_delegates_to_connection
|
155
|
+
TestIndex.connection.expects(:get_mapping).with("test", "test")
|
156
|
+
TestIndex.get_mapping
|
157
|
+
end
|
106
158
|
|
107
|
-
|
159
|
+
def test_refresh_works
|
160
|
+
TestIndex.create_index
|
161
|
+
TestIndex.refresh
|
162
|
+
ensure
|
163
|
+
TestIndex.delete_index if TestIndex.index_exists?
|
164
|
+
end
|
108
165
|
|
109
|
-
|
166
|
+
def test_refresh_delegates_to_connection
|
167
|
+
TestIndex.connection.expects(:refresh).with("test")
|
168
|
+
TestIndex.refresh
|
169
|
+
end
|
110
170
|
|
111
|
-
|
171
|
+
def test_index_url
|
172
|
+
assert TestIndex.index_url
|
173
|
+
end
|
112
174
|
|
113
|
-
|
175
|
+
def test_index_url_delegates_to_connection
|
176
|
+
TestIndex.connection.expects(:index_url).with("test")
|
177
|
+
TestIndex.index_url
|
114
178
|
|
179
|
+
SearchFlip::Config[:index_prefix] = "prefix-"
|
180
|
+
TestIndex.connection.expects(:index_url).with("prefix-test")
|
181
|
+
TestIndex.index_url
|
182
|
+
ensure
|
115
183
|
SearchFlip::Config[:index_prefix] = nil
|
116
184
|
end
|
117
185
|
|
118
186
|
def test_type_url
|
119
|
-
|
120
|
-
|
121
|
-
ProductIndex.stubs(:type_name).returns("products2")
|
187
|
+
assert TestIndex.type_url
|
188
|
+
end
|
122
189
|
|
123
|
-
|
190
|
+
def test_type_url_delegates_to_connection
|
191
|
+
TestIndex.connection.expects(:type_url).with("test", "test")
|
192
|
+
TestIndex.type_url
|
124
193
|
end
|
125
194
|
|
126
195
|
def test_import_object
|
@@ -376,7 +445,7 @@ class SearchFlip::IndexTest < SearchFlip::TestCase
|
|
376
445
|
end
|
377
446
|
|
378
447
|
def test_connection
|
379
|
-
assert_equal
|
448
|
+
assert_equal "http://127.0.0.1:9200", ProductIndex.connection.base_url
|
380
449
|
end
|
381
450
|
end
|
382
451
|
|
data/test/test_helper.rb
CHANGED
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.0.0.
|
4
|
+
version: 2.0.0.beta2
|
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-02-
|
11
|
+
date: 2019-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -193,6 +193,7 @@ files:
|
|
193
193
|
- LICENSE.txt
|
194
194
|
- README.md
|
195
195
|
- Rakefile
|
196
|
+
- UPDATING.md
|
196
197
|
- docker-compose.yml
|
197
198
|
- lib/search_flip.rb
|
198
199
|
- lib/search_flip/aggregatable.rb
|