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