elastics 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/README.md +45 -9
- data/lib/elastics/active_record/helper_methods.rb +50 -12
- data/lib/elastics/active_record/instrumentation.rb +1 -1
- data/lib/elastics/active_record/search_result.rb +5 -31
- data/lib/elastics/auto_refresh.rb +48 -0
- data/lib/elastics/client/bulk.rb +49 -0
- data/lib/elastics/client.rb +20 -5
- data/lib/elastics/result/search.rb +43 -0
- data/lib/elastics/result.rb +5 -0
- data/lib/elastics/tasks/indices.rb +2 -2
- data/lib/elastics/tasks/mappings.rb +1 -1
- data/lib/elastics/tasks/migrations.rb +15 -4
- data/lib/elastics/version.rb +1 -1
- data/lib/elastics/version_manager.rb +1 -1
- data/lib/elastics.rb +5 -5
- data/spec/lib/elastics/auto_refresh_spec.rb +36 -0
- data/spec/lib/elastics/client/bulk_spec.rb +57 -0
- data/spec/lib/elastics/client_spec.rb +34 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c6528a83756461e3f88a64c932e6f6cd4a572e
|
4
|
+
data.tar.gz: 329c63ad74333cee9dc57581ca8ac626973dea3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aba73c791bb368035b51ed5d93994fa27648c442f77ed7992749b5bb5ee5ee823a17e33d5449d0d8a1f293dd830ff01501405287ca1dc563df644c3bb3da68ba
|
7
|
+
data.tar.gz: d687176c8013f6196d0ebc0340aaa6e194e5719b700fdbb688159ca2ca6ffda3694e144e0b55c064fcb63b629299288121b9dbd25ba61876318092089360cafa
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
[![Code Climate](https://codeclimate.com/github/printercu/elastics-rb/badges/gpa.svg)](https://codeclimate.com/github/printercu/elastics-rb)
|
4
4
|
[![Build Status](https://travis-ci.org/printercu/elastics-rb.svg)](https://travis-ci.org/printercu/elastics-rb)
|
5
5
|
|
6
|
-
Simple ElasticSearch client.
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
6
|
+
Simple ElasticSearch client. Everything for deployment & maintaince included.
|
7
|
+
- Basic API only
|
8
|
+
- Transparent aliases management & zero-downtime migrations
|
9
|
+
- Capistrano integration
|
10
|
+
- Auto refresh in tests
|
11
|
+
- Instrumentation
|
10
12
|
|
11
13
|
Fast and thread-safe [httpclient](https://github.com/nahi/httpclient) is under the hood.
|
12
14
|
|
@@ -14,7 +16,7 @@ Fast and thread-safe [httpclient](https://github.com/nahi/httpclient) is under t
|
|
14
16
|
|
15
17
|
```ruby
|
16
18
|
# Gemfile
|
17
|
-
gem 'elastics', '~> 0.
|
19
|
+
gem 'elastics', '~> 0.3' # use version from the badge above
|
18
20
|
# or
|
19
21
|
gem 'elastics', github: 'printercu/elastics-rb'
|
20
22
|
```
|
@@ -34,10 +36,10 @@ client = Elastics::Client.new(options)
|
|
34
36
|
# :resurrect_timeout - timeout to mark dead host as alive in cluster-mode (default 10)
|
35
37
|
|
36
38
|
# basic request
|
37
|
-
client.request(
|
38
|
-
#
|
39
|
+
client.request(params)
|
40
|
+
# params is hash with
|
39
41
|
# :method - default :get
|
40
|
-
# :
|
42
|
+
# :body - post body
|
41
43
|
# :query - query string params
|
42
44
|
# :index, :type, :id - query path params to override defaults
|
43
45
|
|
@@ -50,12 +52,22 @@ client.get(id)
|
|
50
52
|
client.get(params) # as usual
|
51
53
|
|
52
54
|
# other shortcuts (set method & id)
|
53
|
-
client.put_mapping(index: index, type: type,
|
55
|
+
client.put_mapping(index: index, type: type, body: mapping)
|
54
56
|
client.search(params)
|
55
57
|
client.index(params) # PUT if :id is set, otherwise POST
|
56
58
|
|
57
59
|
# utils
|
58
60
|
client.index_exists?(name)
|
61
|
+
|
62
|
+
# bulk
|
63
|
+
client.bulk(params) do |bulk|
|
64
|
+
# if first param is not a Hash it's converted to {_id: param}
|
65
|
+
bulk.index override_params, data
|
66
|
+
bulk.create id, data
|
67
|
+
bulk.update id, script
|
68
|
+
bulk.update_doc id, fields
|
69
|
+
bulk.delete id
|
70
|
+
end
|
59
71
|
```
|
60
72
|
|
61
73
|
When using cluster-mode you should also install `gem 'thread_safe'`.
|
@@ -65,6 +77,7 @@ When using cluster-mode you should also install `gem 'thread_safe'`.
|
|
65
77
|
```ruby
|
66
78
|
class User < ActiveRecord::Base
|
67
79
|
indexed_with_elastics
|
80
|
+
# it'll set after_commit callbacks and add helper methods
|
68
81
|
# optionally pass :index, :type
|
69
82
|
|
70
83
|
# optionally override to export only selected fields
|
@@ -73,9 +86,14 @@ class User < ActiveRecord::Base
|
|
73
86
|
end
|
74
87
|
end
|
75
88
|
|
89
|
+
User.elastics # Elastics::Client instance
|
90
|
+
User.elastics_params # hash with index & type values for the model
|
91
|
+
User.request_elastics(params) # performs request merging params with elastics_params
|
76
92
|
User.search_elastics(data)
|
77
93
|
# Returns Elastics::ActiveRecord::SearchResult object with some useful methods
|
78
94
|
```
|
95
|
+
Check out [HelperMethods](https://github.com/printercu/elastics-rb/blob/master/lib/elastics/active_record/helper_methods.rb)
|
96
|
+
for more information.
|
79
97
|
|
80
98
|
#### Configure
|
81
99
|
```yml
|
@@ -156,6 +174,21 @@ end
|
|
156
174
|
Also you need to install `active_support` & require
|
157
175
|
`active_support/core_ext/object` to be able to run tasks.
|
158
176
|
|
177
|
+
### Auto refresh index
|
178
|
+
Add `Elastics::AutoRefresh.enable!` to your test helper,
|
179
|
+
this will run `POST /:index/_refresh` request after each modifying request.
|
180
|
+
You can also use it for a block or skip auto refresh after it was enabled:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
# enable test mode in rspec's around filter
|
184
|
+
around { |ex| Elastics::AutoRefresh.enable! { ex.run } }
|
185
|
+
|
186
|
+
# disable auto refresh for block & perform single refresh
|
187
|
+
# assume test mode is enabled here
|
188
|
+
Elastics::AutoRefresh.disable! { Model.reindex_elastics }
|
189
|
+
Model.refresh_elastics
|
190
|
+
```
|
191
|
+
|
159
192
|
### Use with capistrano
|
160
193
|
Add following lines to your `deploy.rb` and all rake tasks will be available in cap.
|
161
194
|
|
@@ -170,5 +203,8 @@ Indices & rake options can be passed like this:
|
|
170
203
|
cap --dry-run elastics:migrate INDICES=index1,index2 ES_OPTIONS='full=true no_drop=true'
|
171
204
|
```
|
172
205
|
|
206
|
+
## Other versions
|
207
|
+
[elastics for node.js](https://github.com/printercu/elastics)
|
208
|
+
|
173
209
|
## License
|
174
210
|
MIT
|
@@ -8,19 +8,26 @@ module Elastics
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
def
|
12
|
-
|
11
|
+
def elastics_params
|
12
|
+
{
|
13
13
|
index: elastics_index_name,
|
14
14
|
type: elastics_type_name,
|
15
15
|
model: self,
|
16
|
-
}
|
17
|
-
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def request_elastics(params)
|
20
|
+
elastics.request(elastics_params.merge!(params))
|
21
|
+
end
|
22
|
+
|
23
|
+
def bulk_elastics(params = {}, &block)
|
24
|
+
elastics.bulk(elastics_params.merge!(params), &block)
|
18
25
|
end
|
19
26
|
|
20
27
|
def search_elastics(data = {}, options = {})
|
21
28
|
request = {
|
22
29
|
id: :_search,
|
23
|
-
|
30
|
+
body: data,
|
24
31
|
}
|
25
32
|
if routing = options[:routing]
|
26
33
|
request[:query] = {routing: routing}
|
@@ -37,23 +44,54 @@ module Elastics
|
|
37
44
|
request_elastics(method: :get, id: :_mapping)
|
38
45
|
end
|
39
46
|
|
40
|
-
def
|
41
|
-
|
47
|
+
def index_all_elastics(*args)
|
48
|
+
find_in_batches(*args) do |batch|
|
49
|
+
bulk_elastics do |bulk|
|
50
|
+
batch.each do |record|
|
51
|
+
bulk.index record.id, record.to_elastics
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Reindexes records with `#index_all_elastics`. If model has scope
|
58
|
+
# named `reindex_scope`, this method will apply it.
|
59
|
+
#
|
60
|
+
# Also supports `:updated_after` option to reindex only updated records.
|
61
|
+
# Nothing is performed when `:updated_after` is set but model
|
62
|
+
# has not `updated_at` column.
|
63
|
+
def reindex_elastics(options = {})
|
64
|
+
scope = respond_to?(:reindex_scope) ? reindex_scope : all
|
65
|
+
if after = options.delete(:updated_after)
|
66
|
+
if updated_at = arel_table[:updated_at]
|
67
|
+
scope = scope.where(updated_at.gt(after))
|
68
|
+
else
|
69
|
+
return
|
70
|
+
end
|
71
|
+
end
|
72
|
+
scope.index_all_elastics(options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def refresh_elastics
|
76
|
+
request_elastics(method: :post, type: nil, id: :_refresh)
|
42
77
|
end
|
43
78
|
end
|
44
79
|
|
45
80
|
def index_elastics
|
46
|
-
self.class.request_elastics(method: :post, id: id,
|
81
|
+
self.class.request_elastics(method: :post, id: id, body: to_elastics)
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_elastics(data)
|
85
|
+
self.class.request_elastics(method: :post, id: "#{id}/_update", body: data)
|
47
86
|
end
|
48
87
|
|
49
|
-
def
|
50
|
-
|
51
|
-
doc: fields
|
52
|
-
})
|
88
|
+
def update_elastics_doc(fields)
|
89
|
+
update_elastics(doc: fields)
|
53
90
|
end
|
54
91
|
|
55
92
|
def delete_elastics
|
56
93
|
self.class.request_elastics(method: :delete, id: id)
|
94
|
+
rescue NotFound
|
57
95
|
end
|
58
96
|
end
|
59
97
|
end
|
@@ -1,48 +1,22 @@
|
|
1
1
|
module Elastics
|
2
2
|
module ActiveRecord
|
3
|
-
class SearchResult
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(model, result, options = {})
|
3
|
+
class SearchResult < Result::Search
|
4
|
+
def initialize(model, response, options = {})
|
7
5
|
@model = model
|
8
|
-
|
9
|
-
@options = options
|
10
|
-
end
|
11
|
-
|
12
|
-
def hits
|
13
|
-
@hits ||= @result['hits'.freeze]
|
6
|
+
super response, options
|
14
7
|
end
|
15
8
|
|
9
|
+
# super.map(&:to_i)
|
16
10
|
def ids
|
17
11
|
@ids ||= hits['hits'.freeze].map { |x| x['_id'.freeze].to_i }
|
18
12
|
end
|
19
13
|
|
20
|
-
def ids_to_find
|
21
|
-
@ids_to_find ||= begin
|
22
|
-
limit = @options[:limit]
|
23
|
-
limit ? ids[0...limit] : ids
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def rest_ids
|
28
|
-
limit = @options[:limit]
|
29
|
-
limit ? ids[limit..-1] : []
|
30
|
-
end
|
31
|
-
|
32
14
|
def collection
|
33
15
|
@collection ||= @model.find_all_ordered ids_to_find
|
34
16
|
end
|
35
17
|
|
36
18
|
def relation
|
37
|
-
@model.where
|
38
|
-
end
|
39
|
-
|
40
|
-
def aggregations
|
41
|
-
@aggregations ||= @result['aggregations'.freeze]
|
42
|
-
end
|
43
|
-
|
44
|
-
def total
|
45
|
-
hits['total'.freeze]
|
19
|
+
@model.where(id: ids_to_find)
|
46
20
|
end
|
47
21
|
end
|
48
22
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Elastics
|
2
|
+
module AutoRefresh
|
3
|
+
METHODS = %w(put post patch delete)
|
4
|
+
SKIP_IDS = %w(_refresh _search)
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def enabled?
|
8
|
+
Thread.current[:elastics_test_mode]
|
9
|
+
end
|
10
|
+
|
11
|
+
def enabled=(value)
|
12
|
+
value = !!value
|
13
|
+
Client.send(:include, self) if value && !Client.include?(self)
|
14
|
+
Thread.current[:elastics_test_mode] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def use(value)
|
18
|
+
old_value = enabled?
|
19
|
+
self.enabled = value
|
20
|
+
block_given? ? yield : value
|
21
|
+
ensure
|
22
|
+
self.enabled = old_value if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def enable!(&block)
|
26
|
+
use(true, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable!(&block)
|
30
|
+
use(false, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def included(base)
|
34
|
+
base.send :alias_method, :request_without_auto_refresh, :request
|
35
|
+
base.send :alias_method, :request, :request_with_auto_refresh
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def request_with_auto_refresh(params)
|
40
|
+
request_without_auto_refresh(params).tap do
|
41
|
+
next unless AutoRefresh.enabled?
|
42
|
+
next if SKIP_IDS.include?(params[:id].to_s.downcase)
|
43
|
+
next unless METHODS.include?(params[:method].to_s.downcase)
|
44
|
+
refresh(params[:index])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Elastics
|
2
|
+
class Client
|
3
|
+
module Bulk
|
4
|
+
def bulk(params = {})
|
5
|
+
builder = Builder.new
|
6
|
+
yield builder
|
7
|
+
if builder.any?
|
8
|
+
request({body: builder.body, method: :post, id: :_bulk}.merge! params)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Builder
|
13
|
+
attr_reader :actions
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@actions = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def any?
|
20
|
+
@actions.any?
|
21
|
+
end
|
22
|
+
|
23
|
+
def body
|
24
|
+
@actions.map(&:to_json).join("\n".freeze) + "\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_action(action, params, data = nil)
|
28
|
+
params = {_id: params} unless params.is_a?(Hash)
|
29
|
+
@actions << {action => params}
|
30
|
+
@actions << data if data
|
31
|
+
end
|
32
|
+
|
33
|
+
[:index, :create, :update].each do |action|
|
34
|
+
define_method(action) do |params, data|
|
35
|
+
add_action(action, params, data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_doc(params, fields)
|
40
|
+
update(params, doc: fields)
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(params)
|
44
|
+
add_action(:delete, params)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/elastics/client.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'json'
|
1
2
|
require 'httpclient'
|
2
3
|
|
3
4
|
module Elastics
|
@@ -6,6 +7,9 @@ module Elastics
|
|
6
7
|
|
7
8
|
autoload :Cluster, 'elastics/client/cluster'
|
8
9
|
|
10
|
+
require 'elastics/client/bulk'
|
11
|
+
include Bulk
|
12
|
+
|
9
13
|
attr_writer :index, :type
|
10
14
|
attr_reader :client
|
11
15
|
|
@@ -46,9 +50,10 @@ module Elastics
|
|
46
50
|
str
|
47
51
|
end
|
48
52
|
|
49
|
-
def request(params)
|
53
|
+
def request(params = {})
|
50
54
|
method = params[:method] || :get
|
51
|
-
body = params[:
|
55
|
+
body = params[:body]
|
56
|
+
body = body.to_json if body && !body.is_a?(String)
|
52
57
|
res = http_request(method, request_path(params), params[:query], body, params)
|
53
58
|
status = res.status
|
54
59
|
return JSON.parse(res.body) if 300 > status
|
@@ -68,6 +73,7 @@ module Elastics
|
|
68
73
|
end
|
69
74
|
|
70
75
|
def delete!(params)
|
76
|
+
params = {id: params} unless params.is_a?(Hash)
|
71
77
|
params[:method] = :delete
|
72
78
|
request params
|
73
79
|
end
|
@@ -89,7 +95,7 @@ module Elastics
|
|
89
95
|
end
|
90
96
|
|
91
97
|
def set(id, data)
|
92
|
-
request(id: id,
|
98
|
+
request(id: id, body: data, method: :put)
|
93
99
|
end
|
94
100
|
|
95
101
|
def put_mapping(params)
|
@@ -98,10 +104,10 @@ module Elastics
|
|
98
104
|
request(params)
|
99
105
|
end
|
100
106
|
|
101
|
-
def search(params)
|
107
|
+
def search(params, *args)
|
102
108
|
params[:id] = :_search
|
103
109
|
params[:method] = :post
|
104
|
-
request(params)
|
110
|
+
Result::Search.new(request(params), *args)
|
105
111
|
end
|
106
112
|
|
107
113
|
def index(params)
|
@@ -112,6 +118,15 @@ module Elastics
|
|
112
118
|
!!get(index: index, type: nil, id: :_mapping)
|
113
119
|
end
|
114
120
|
|
121
|
+
def refresh!(index = nil)
|
122
|
+
request(method: :post, index: index, type: nil, id: :_refresh)
|
123
|
+
end
|
124
|
+
|
125
|
+
def refresh(*args)
|
126
|
+
refresh!(*args)
|
127
|
+
rescue NotFound
|
128
|
+
end
|
129
|
+
|
115
130
|
private
|
116
131
|
# Endpoint for low-level request. For easy host highjacking & instrumentation.
|
117
132
|
# Params are not used directly but kept for instrumentation purpose.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Result
|
3
|
+
class Search
|
4
|
+
attr_reader :response
|
5
|
+
|
6
|
+
def initialize(response, options = {})
|
7
|
+
@response = response
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def hits
|
12
|
+
@hits ||= @response['hits'.freeze]
|
13
|
+
end
|
14
|
+
|
15
|
+
def ids
|
16
|
+
@ids ||= hits['hits'.freeze].map { |x| x['_id'.freeze] }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Allows to split ids into two parts, if you want to fetch from primary DB
|
20
|
+
# less then was found. This method returns the first part,
|
21
|
+
# `rest_ids` - the second.
|
22
|
+
def ids_to_find
|
23
|
+
@ids_to_find ||= begin
|
24
|
+
limit = @options[:limit]
|
25
|
+
limit ? ids[0...limit] : ids
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def rest_ids
|
30
|
+
limit = @options[:limit]
|
31
|
+
limit ? ids[limit..-1] : []
|
32
|
+
end
|
33
|
+
|
34
|
+
def aggregations
|
35
|
+
@aggregations ||= @response['aggregations'.freeze]
|
36
|
+
end
|
37
|
+
|
38
|
+
def total
|
39
|
+
hits['total'.freeze]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -58,7 +58,7 @@ module Elastics
|
|
58
58
|
log_msg << ' - Skipping: exists' if exists
|
59
59
|
log log_msg
|
60
60
|
unless exists
|
61
|
-
client.put(index: versioned_index,
|
61
|
+
client.put(index: versioned_index, body: indices_settings[index])
|
62
62
|
end
|
63
63
|
end
|
64
64
|
manage_aliases :add, options if version.to_s == 'current'
|
@@ -97,7 +97,7 @@ module Elastics
|
|
97
97
|
def post_aliases(options = {}, &block)
|
98
98
|
actions = each_filtered(indices, options[:indices]).map(&block).flatten
|
99
99
|
log "Posting aliases: #{actions.inspect}"
|
100
|
-
client.post id: :_aliases,
|
100
|
+
client.post id: :_aliases, body: {actions: actions} if actions.any?
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -17,7 +17,7 @@ module Elastics
|
|
17
17
|
versioned_index = versioned_index_name(index, version)
|
18
18
|
log "Putting mapping #{index}/#{type} (#{versioned_index}/#{type})"
|
19
19
|
client.put_mapping index: versioned_index, type: type,
|
20
|
-
|
20
|
+
body: mappings[type]
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -8,22 +8,33 @@ module Elastics
|
|
8
8
|
|
9
9
|
def migrate!(options = {})
|
10
10
|
options_next = options.merge version: :next
|
11
|
+
need_reindex = options.fetch(:reindex, true)
|
11
12
|
drop_indices(options_next)
|
12
13
|
create_indices(options_next)
|
13
14
|
put_mappings(options_next)
|
14
|
-
reindex(options_next) if
|
15
|
+
started_at = reindex(options_next) if need_reindex
|
15
16
|
forward_aliases(options)
|
17
|
+
if need_reindex
|
18
|
+
reindex(options.merge(version: :current, updated_after: started_at))
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
22
|
+
# Runs `#reindex_elastics` on matching models.
|
23
|
+
# Returns hash with timestamps with reindex start time for each model.
|
24
|
+
# Supports this kind of hash as `:updated_after` option, to reindex
|
25
|
+
# only updated records.
|
18
26
|
def reindex(options = {})
|
19
27
|
version = options.fetch(:version, :current)
|
28
|
+
updated_after = options.fetch(:updated_after, {})
|
20
29
|
Rails.application.eager_load! if defined?(Rails)
|
21
30
|
VersionManager.use_version version do
|
22
|
-
models_to_reindex(options).
|
31
|
+
Hash[models_to_reindex(options).map do |model|
|
32
|
+
started_at = Time.now
|
23
33
|
log "Reindexing #{model.elastics_index_base} into " \
|
24
34
|
"#{model.elastics_index_name}/#{model.elastics_type_name}"
|
25
|
-
model.reindex_elastics
|
26
|
-
|
35
|
+
model.reindex_elastics(updated_after: updated_after[model])
|
36
|
+
[model, started_at]
|
37
|
+
end]
|
27
38
|
end
|
28
39
|
end
|
29
40
|
|
data/lib/elastics/version.rb
CHANGED
data/lib/elastics.rb
CHANGED
@@ -3,12 +3,12 @@ module Elastics
|
|
3
3
|
class NotFound < Error; end
|
4
4
|
|
5
5
|
require 'elastics/client'
|
6
|
-
require 'elastics/version_manager'
|
7
|
-
require 'elastics/query_helper'
|
8
6
|
|
9
|
-
autoload :
|
10
|
-
|
11
|
-
|
7
|
+
autoload :AutoRefresh, 'elastics/auto_refresh'
|
8
|
+
autoload :Tasks, 'elastics/tasks'
|
9
|
+
autoload :QueryHelper, 'elastics/query_helper'
|
10
|
+
autoload :Result, 'elastics/result'
|
11
|
+
autoload :VersionManager, 'elastics/version_manager'
|
12
12
|
|
13
13
|
class << self
|
14
14
|
attr_reader :models
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Elastics::AutoRefresh do
|
4
|
+
let(:client) { Elastics::Client.new }
|
5
|
+
let(:response) { OpenStruct.new(body: '{}', status: 200) }
|
6
|
+
before { allow(client).to receive(:http_request) { response } }
|
7
|
+
|
8
|
+
describe '.enable!' do
|
9
|
+
around { |ex| described_class.enable! { ex.run } }
|
10
|
+
|
11
|
+
context 'for GET & search request' do
|
12
|
+
it 'doesn`t invoke refresh' do
|
13
|
+
expect(client).to_not receive(:refresh)
|
14
|
+
client.get 1
|
15
|
+
client.search query: {match_all: {}}
|
16
|
+
client.request method: :get, id: :_mapping
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'for POST, PUT & DELETE requests' do
|
21
|
+
it 'invokes refresh after each request' do
|
22
|
+
expect(client).to receive(:refresh).exactly(3).times
|
23
|
+
client.post id: 1
|
24
|
+
client.put_mapping type: {fields: {}}
|
25
|
+
client.delete id: 2
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'invokes refresh after each request, not wrapped in .disable! block' do
|
29
|
+
expect(client).to receive(:refresh).exactly(2).times
|
30
|
+
client.post id: 1
|
31
|
+
described_class.disable! { client.put_mapping type: {fields: {}} }
|
32
|
+
client.delete id: 2
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Elastics::Client::Bulk::Builder do
|
4
|
+
let(:instance) { described_class.new }
|
5
|
+
|
6
|
+
describe '#add_action' do
|
7
|
+
context 'if params is hash' do
|
8
|
+
it 'add param as is' do
|
9
|
+
expect { instance.add_action :action, {test: 1} }.
|
10
|
+
to change { instance.actions }.
|
11
|
+
from([]).
|
12
|
+
to([{action: {test: 1}}])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'if params is not a hash' do
|
17
|
+
it 'treats params as id' do
|
18
|
+
expect { instance.add_action :action, 1 }.
|
19
|
+
to change { instance.actions }.
|
20
|
+
from([]).
|
21
|
+
to([{action: {_id: 1}}])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'adds data as is' do
|
26
|
+
expect { instance.add_action :action, {test: 1}, :data }.
|
27
|
+
to change { instance.actions }.
|
28
|
+
from([]).
|
29
|
+
to([{action: {test: 1}}, :data])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe Elastics::Client do
|
35
|
+
let(:client) { Elastics::Client.new }
|
36
|
+
|
37
|
+
describe '#bulk' do
|
38
|
+
context 'when no actions added' do
|
39
|
+
it 'should not invoke #request' do
|
40
|
+
expect(client).to_not receive(:request)
|
41
|
+
client.bulk {}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when some actions added' do
|
46
|
+
it 'should invoke request' do
|
47
|
+
expect(client).to receive(:request).with(
|
48
|
+
id: :_bulk,
|
49
|
+
method: :post,
|
50
|
+
index: :index1,
|
51
|
+
body: "{\"delete\":{\"_id\":1}}\n",
|
52
|
+
)
|
53
|
+
client.bulk(index: :index1) { |x| x.delete 1 }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Elastics::Client do
|
4
|
+
let(:instance) { described_class.new }
|
5
|
+
let(:index_name) { 'elastics_test' }
|
6
|
+
|
7
|
+
describe '#refresh!' do
|
8
|
+
subject { instance.refresh!(index_name) }
|
9
|
+
|
10
|
+
context 'when index exists' do
|
11
|
+
before { instance.post(index: index_name) }
|
12
|
+
after { instance.delete(index: index_name) }
|
13
|
+
it { should be }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when index does not exist' do
|
17
|
+
it { expect { subject }.to raise_error(Elastics::NotFound) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#refresh' do
|
22
|
+
subject { instance.refresh(index_name) }
|
23
|
+
|
24
|
+
context 'when index exists' do
|
25
|
+
before { instance.post(index: index_name) }
|
26
|
+
after { instance.delete(index: index_name) }
|
27
|
+
it { should be }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when index does not exist' do
|
31
|
+
it { should be_nil }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Melentiev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httpclient
|
@@ -115,11 +115,15 @@ files:
|
|
115
115
|
- lib/elastics/active_record/model_schema.rb
|
116
116
|
- lib/elastics/active_record/search_result.rb
|
117
117
|
- lib/elastics/active_record/tasks_config.rb
|
118
|
+
- lib/elastics/auto_refresh.rb
|
118
119
|
- lib/elastics/capistrano.rb
|
119
120
|
- lib/elastics/client.rb
|
121
|
+
- lib/elastics/client/bulk.rb
|
120
122
|
- lib/elastics/client/cluster.rb
|
121
123
|
- lib/elastics/query_helper.rb
|
122
124
|
- lib/elastics/railtie.rb
|
125
|
+
- lib/elastics/result.rb
|
126
|
+
- lib/elastics/result/search.rb
|
123
127
|
- lib/elastics/tasks.rb
|
124
128
|
- lib/elastics/tasks/config.rb
|
125
129
|
- lib/elastics/tasks/indices.rb
|
@@ -128,7 +132,10 @@ files:
|
|
128
132
|
- lib/elastics/version.rb
|
129
133
|
- lib/elastics/version_manager.rb
|
130
134
|
- lib/tasks/elastics.rake
|
135
|
+
- spec/lib/elastics/auto_refresh_spec.rb
|
136
|
+
- spec/lib/elastics/client/bulk_spec.rb
|
131
137
|
- spec/lib/elastics/client/cluster_spec.rb
|
138
|
+
- spec/lib/elastics/client_spec.rb
|
132
139
|
- spec/spec_helper.rb
|
133
140
|
homepage: http://github.com/printercu/elastics-rb
|
134
141
|
licenses:
|
@@ -155,6 +162,8 @@ signing_key:
|
|
155
162
|
specification_version: 4
|
156
163
|
summary: ElasticSearch client with ActiveRecord integration
|
157
164
|
test_files:
|
165
|
+
- spec/lib/elastics/auto_refresh_spec.rb
|
166
|
+
- spec/lib/elastics/client/bulk_spec.rb
|
158
167
|
- spec/lib/elastics/client/cluster_spec.rb
|
168
|
+
- spec/lib/elastics/client_spec.rb
|
159
169
|
- spec/spec_helper.rb
|
160
|
-
has_rdoc:
|