esse 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/esse/cli/event_listener.rb +4 -5
- data/lib/esse/cli/generate.rb +14 -16
- data/lib/esse/cli/index/close.rb +1 -1
- data/lib/esse/cli/index/create.rb +1 -1
- data/lib/esse/cli/index/delete.rb +1 -1
- data/lib/esse/cli/index/import.rb +2 -2
- data/lib/esse/cli/index/open.rb +1 -1
- data/lib/esse/cli/index/reset.rb +1 -1
- data/lib/esse/cli/index/update_aliases.rb +2 -2
- data/lib/esse/cli/index/update_mapping.rb +8 -3
- data/lib/esse/cli/index/update_settings.rb +1 -1
- data/lib/esse/cli/index.rb +9 -4
- data/lib/esse/cli/templates/collection.rb.erb +6 -6
- data/lib/esse/cli/templates/{serializer.rb.erb → document.rb.erb} +6 -6
- data/lib/esse/cli/templates/index.rb.erb +39 -34
- data/lib/esse/cli.rb +5 -0
- data/lib/esse/cluster.rb +38 -12
- data/lib/esse/core.rb +7 -3
- data/lib/esse/deprecations/cluster.rb +5 -5
- data/lib/esse/deprecations/deprecate.rb +29 -0
- data/lib/esse/deprecations/index.rb +21 -3
- data/lib/esse/deprecations/index_backend_delegator.rb +217 -0
- data/lib/esse/deprecations/repository.rb +19 -4
- data/lib/esse/deprecations/repository_backend_delegator.rb +110 -0
- data/lib/esse/deprecations/serializer.rb +14 -0
- data/lib/esse/deprecations.rb +4 -0
- data/lib/esse/{serializer.rb → document.rb} +17 -2
- data/lib/esse/dynamic_template.rb +4 -0
- data/lib/esse/errors.rb +8 -1
- data/lib/esse/events.rb +13 -5
- data/lib/esse/hash_document.rb +1 -1
- data/lib/esse/import/bulk.rb +21 -11
- data/lib/esse/index/aliases.rb +50 -0
- data/lib/esse/index/attributes.rb +14 -5
- data/lib/esse/index/base.rb +17 -53
- data/lib/esse/index/documents.rb +236 -0
- data/lib/esse/index/indices.rb +171 -0
- data/lib/esse/index/object_document_mapper.rb +0 -59
- data/lib/esse/index/type.rb +2 -3
- data/lib/esse/index.rb +4 -3
- data/lib/esse/null_document.rb +1 -1
- data/lib/esse/repository/{backend.rb → documents.rb} +2 -3
- data/lib/esse/repository/object_document_mapper.rb +20 -20
- data/lib/esse/repository.rb +1 -2
- data/lib/esse/search/query.rb +8 -8
- data/lib/esse/template_loader.rb +1 -1
- data/lib/esse/transport/aliases.rb +36 -0
- data/lib/esse/transport/documents.rb +199 -0
- data/lib/esse/transport/health.rb +30 -0
- data/lib/esse/transport/indices.rb +192 -0
- data/lib/esse/{client_proxy → transport}/search.rb +9 -5
- data/lib/esse/transport.rb +44 -0
- data/lib/esse/version.rb +1 -1
- metadata +28 -28
- data/lib/esse/backend/index/aliases.rb +0 -73
- data/lib/esse/backend/index/close.rb +0 -54
- data/lib/esse/backend/index/create.rb +0 -67
- data/lib/esse/backend/index/delete.rb +0 -39
- data/lib/esse/backend/index/documents.rb +0 -270
- data/lib/esse/backend/index/existance.rb +0 -22
- data/lib/esse/backend/index/open.rb +0 -54
- data/lib/esse/backend/index/refresh.rb +0 -45
- data/lib/esse/backend/index/reset.rb +0 -33
- data/lib/esse/backend/index/update.rb +0 -143
- data/lib/esse/backend/index.rb +0 -56
- data/lib/esse/backend/repository_backend.rb +0 -105
- data/lib/esse/client_proxy.rb +0 -32
- data/lib/esse/index/backend.rb +0 -14
@@ -31,17 +31,20 @@ module Esse
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def index_prefix=(value)
|
34
|
-
|
34
|
+
if value == false
|
35
|
+
@index_prefix = nil
|
36
|
+
return
|
37
|
+
end
|
35
38
|
|
36
39
|
@index_prefix = Hstring.new(value.to_s).underscore.presence
|
37
40
|
end
|
38
41
|
|
39
|
-
def
|
40
|
-
@
|
42
|
+
def index_suffix=(value)
|
43
|
+
@index_suffix = Hstring.new(value.to_s).underscore.presence
|
41
44
|
end
|
42
45
|
|
43
|
-
def
|
44
|
-
@
|
46
|
+
def index_suffix
|
47
|
+
@index_suffix
|
45
48
|
end
|
46
49
|
|
47
50
|
def uname
|
@@ -91,6 +94,12 @@ module Esse
|
|
91
94
|
def normalized_name
|
92
95
|
Hstring.new(name).underscore.tr('/', '_').sub(/_(index)$/, '')
|
93
96
|
end
|
97
|
+
|
98
|
+
def build_real_index_name(suffix = nil)
|
99
|
+
suffix = Hstring.new(suffix).underscore.presence || index_suffix || Esse.timestamp
|
100
|
+
|
101
|
+
index_name(suffix: suffix)
|
102
|
+
end
|
94
103
|
end
|
95
104
|
|
96
105
|
extend ClassMethods
|
data/lib/esse/index/base.rb
CHANGED
@@ -3,48 +3,23 @@
|
|
3
3
|
module Esse
|
4
4
|
class Index
|
5
5
|
module ClassMethods
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
# class Baz < EsIndex(:v1)
|
21
|
-
# # Uses :v1 elasticsearch client connection
|
22
|
-
# end
|
23
|
-
# end
|
24
|
-
def def_Index(index_module) # rubocop:disable Naming/MethodName
|
25
|
-
tap do |model|
|
26
|
-
index_module.define_singleton_method(:Index) do |source|
|
27
|
-
model.Index(source)
|
28
|
-
end
|
6
|
+
# Sets the client_id associated with the Index class.
|
7
|
+
# This can be used directly on Esse::Index to set the :default es cluster
|
8
|
+
# to be used by subclasses, or to override the es client used for specific indices:
|
9
|
+
# Esse::Index.cluster_id = :v1
|
10
|
+
# ArtistIndex = Class.new(Esse::Index)
|
11
|
+
# ArtistIndex.cluster_id = :v2
|
12
|
+
# @param [Symbol, Esse::Cluster, NilClass] source the cluster id or the cluster instance
|
13
|
+
# @return [Symbol] the cluster id
|
14
|
+
# @raise [ArgumentError] if the cluster id is not defined in the Esse.config
|
15
|
+
def cluster_id=(source)
|
16
|
+
if source.nil?
|
17
|
+
@cluster_id = nil
|
18
|
+
return
|
29
19
|
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Lets you create a Index subclass with its elasticsearch cluster
|
33
|
-
#
|
34
|
-
# Example:
|
35
|
-
# # Using a custom cluster
|
36
|
-
# Esse.config.cluster(:v1).client = Elasticsearch::Client.new
|
37
|
-
# class UsersIndex < Esse::Index(:v1)
|
38
|
-
# end
|
39
|
-
#
|
40
|
-
# # Using :default cluster
|
41
|
-
# class UsersIndex < Esse::Index
|
42
|
-
# end
|
43
|
-
def Index(source) # rubocop:disable Naming/MethodName
|
44
|
-
klass = Class.new(self)
|
45
20
|
|
46
21
|
valid_ids = Esse.config.cluster_ids
|
47
|
-
|
22
|
+
new_id = \
|
48
23
|
case source
|
49
24
|
when Esse::Cluster
|
50
25
|
source.id
|
@@ -55,7 +30,7 @@ module Esse
|
|
55
30
|
|
56
31
|
msg = <<~MSG
|
57
32
|
We could not resolve the index cluster using the argument %<arg>p. \n
|
58
|
-
It must be previously defined in the `Esse.config' settings. \n
|
33
|
+
It must be previously defined in the `Esse.config.cluster(%<arg>p) { ... }' settings. \n
|
59
34
|
Here is the list of cluster ids we have configured: %<ids>s\n
|
60
35
|
|
61
36
|
You can ignore this cluster id entirely. That way the :default id will be used.\n
|
@@ -63,22 +38,11 @@ module Esse
|
|
63
38
|
class UsersIndex < Esse::Index\n
|
64
39
|
end\n
|
65
40
|
MSG
|
66
|
-
unless
|
41
|
+
unless new_id
|
67
42
|
raise ArgumentError.new, format(msg, arg: source, ids: valid_ids.map(&:inspect).join(', '))
|
68
43
|
end
|
69
44
|
|
70
|
-
|
71
|
-
klass
|
72
|
-
end
|
73
|
-
|
74
|
-
# Sets the client_id associated with the Index class.
|
75
|
-
# This can be used directly on Esse::Index to set the :default es cluster
|
76
|
-
# to be used by subclasses, or to override the es client used for specific indices:
|
77
|
-
# Esse::Index.cluster_id = :v1
|
78
|
-
# ArtistIndex = Class.new(Esse::Index)
|
79
|
-
# ArtistIndex.cluster_id = :v2
|
80
|
-
def cluster_id=(cluster_id)
|
81
|
-
@cluster_id = cluster_id
|
45
|
+
@cluster_id = new_id
|
82
46
|
end
|
83
47
|
|
84
48
|
# @return [Symbol] reads the @cluster_id instance variable or :default
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
class Index
|
5
|
+
module ClassMethods
|
6
|
+
# Retrieves the specified JSON document from an index.
|
7
|
+
#
|
8
|
+
# UsersIndex.get(id: 1) # { '_id' => 1, ... }
|
9
|
+
# UsersIndex.get(id: 'missing') # raise Esse::Transport::NotFoundError
|
10
|
+
#
|
11
|
+
# @param doc [Esse::Document] the document to retrieve
|
12
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
13
|
+
# @option [String, Integer] :id The `_id` of the elasticsearch document
|
14
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
15
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
16
|
+
# @raise [Esse::Transport::NotFoundError] when the doc does not exist
|
17
|
+
# @return [Hash] The elasticsearch document.
|
18
|
+
#
|
19
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
|
20
|
+
def get(doc = nil, suffix: nil, **options)
|
21
|
+
if document?(doc)
|
22
|
+
options[:id] = doc.id
|
23
|
+
options[:type] = doc.type if doc.type?
|
24
|
+
options[:routing] = doc.routing if doc.routing?
|
25
|
+
end
|
26
|
+
require_kwargs!(options, :id)
|
27
|
+
options[:index] = index_name(suffix: suffix)
|
28
|
+
cluster.may_update_type!(options)
|
29
|
+
cluster.api.get(**options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check if a JSON document exists
|
33
|
+
#
|
34
|
+
# UsersIndex.exist?(id: 1) # true
|
35
|
+
# UsersIndex.exist?(id: 'missing') # false
|
36
|
+
#
|
37
|
+
# @param doc [Esse::Document] the document to retrieve
|
38
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
39
|
+
# @option [String, Integer] :id The `_id` of the elasticsearch document
|
40
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
41
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
42
|
+
# @return [Boolean] true if the document exists
|
43
|
+
def exist?(doc = nil, suffix: nil, **options)
|
44
|
+
if document?(doc)
|
45
|
+
options[:id] = doc.id
|
46
|
+
options[:type] = doc.type if doc.type?
|
47
|
+
options[:routing] = doc.routing if doc.routing?
|
48
|
+
end
|
49
|
+
require_kwargs!(options, :id)
|
50
|
+
options[:index] = index_name(suffix: suffix)
|
51
|
+
cluster.may_update_type!(options)
|
52
|
+
cluster.api.exist?(**options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Gets the number of matches for a search query.
|
56
|
+
#
|
57
|
+
# UsersIndex.count # 999
|
58
|
+
# UsersIndex.count(body: { ... }) # 32
|
59
|
+
#
|
60
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
61
|
+
# @option [Hash] :body A query to restrict the results specified with the Query DSL (optional)
|
62
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
63
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
64
|
+
# @return [Integer] amount of documents found
|
65
|
+
#
|
66
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-count.html
|
67
|
+
def count(type: nil, suffix: nil, **options)
|
68
|
+
params = {
|
69
|
+
index: index_name(suffix: suffix),
|
70
|
+
type: type,
|
71
|
+
}
|
72
|
+
cluster.may_update_type!(params)
|
73
|
+
cluster.api.count(**options, **params)['count']
|
74
|
+
end
|
75
|
+
|
76
|
+
# Removes a JSON document from the specified index.
|
77
|
+
#
|
78
|
+
# UsersIndex.delete(id: 1) # true
|
79
|
+
# UsersIndex.delete(id: 'missing') # false
|
80
|
+
#
|
81
|
+
# @param doc [Esse::Document] the document to retrieve
|
82
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
83
|
+
# @option [String, Integer] :id The `_id` of the elasticsearch document
|
84
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
85
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
86
|
+
# @raise [Esse::Transport::NotFoundError] when the doc does not exist
|
87
|
+
#
|
88
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
|
89
|
+
def delete(doc = nil, suffix: nil, **options)
|
90
|
+
if document?(doc)
|
91
|
+
options[:id] = doc.id
|
92
|
+
options[:type] = doc.type if doc.type?
|
93
|
+
options[:routing] = doc.routing if doc.routing?
|
94
|
+
end
|
95
|
+
require_kwargs!(options, :id)
|
96
|
+
options[:index] = index_name(suffix: suffix)
|
97
|
+
cluster.may_update_type!(options)
|
98
|
+
cluster.api.delete(**options)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Updates a document using the specified script.
|
102
|
+
#
|
103
|
+
# UsersIndex.update(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
|
104
|
+
#
|
105
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
106
|
+
# @option [String, Integer] :id The `_id` of the elasticsearch document
|
107
|
+
# @option [Hash] :body the body of the request
|
108
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
109
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
110
|
+
# @raise [Esse::Transport::NotFoundError] when the doc does not exist
|
111
|
+
# @return [Hash] elasticsearch response hash
|
112
|
+
#
|
113
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
|
114
|
+
def update(doc = nil, suffix: nil, **options)
|
115
|
+
if document?(doc)
|
116
|
+
options[:id] = doc.id
|
117
|
+
options[:body] = { doc: doc.source }
|
118
|
+
options[:type] = doc.type if doc.type?
|
119
|
+
options[:routing] = doc.routing if doc.routing?
|
120
|
+
end
|
121
|
+
require_kwargs!(options, :id, :body)
|
122
|
+
options[:index] = index_name(suffix: suffix)
|
123
|
+
cluster.may_update_type!(options)
|
124
|
+
cluster.api.update(**options)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Adds a JSON document to the specified index and makes it searchable. If the document
|
128
|
+
# already exists, updates the document and increments its version.
|
129
|
+
#
|
130
|
+
# UsersIndex::User.index(id: 1, body: { name: 'name' }) # { '_id' => 1, ...}
|
131
|
+
#
|
132
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
133
|
+
# @option [String, Integer] :id The `_id` of the elasticsearch document
|
134
|
+
# @option [Hash] :body The JSON document that will be indexed (Required)
|
135
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
136
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
137
|
+
# @return [Hash] the elasticsearch response Hash
|
138
|
+
#
|
139
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
|
140
|
+
def index(doc = nil, suffix: nil, **options)
|
141
|
+
if document?(doc)
|
142
|
+
options[:id] = doc.id
|
143
|
+
options[:body] = doc.source
|
144
|
+
options[:type] = doc.type if doc.type?
|
145
|
+
options[:routing] = doc.routing if doc.routing?
|
146
|
+
end
|
147
|
+
require_kwargs!(options, :id, :body)
|
148
|
+
options[:index] = index_name(suffix: suffix)
|
149
|
+
cluster.may_update_type!(options)
|
150
|
+
cluster.api.index(**options)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Performs multiple indexing or delete operations in a single API call.
|
154
|
+
# This reduces overhead and can greatly increase indexing speed.
|
155
|
+
#
|
156
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
157
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
158
|
+
# @option [Array<Esse::Document>] :index list of documents to be indexed(Optional)
|
159
|
+
# @option [Array<Esse::Document>] :delete list of documents to be deleted(Optional)
|
160
|
+
# @option [Array<Esse::Document>] :create list of documents to be created(Optional)
|
161
|
+
# @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
|
162
|
+
# @return [Array<Esse::Import::RequestBody>] The list of request bodies. @TODO Change this to a Stats object
|
163
|
+
#
|
164
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-bulk.html
|
165
|
+
# @see https://github.com/elastic/elasticsearch-ruby/blob/main/elasticsearch-api/lib/elasticsearch/api/utils.rb
|
166
|
+
# @see https://github.com/elastic/elasticsearch-ruby/blob/main/elasticsearch-api/lib/elasticsearch/api/actions/bulk.rb
|
167
|
+
def bulk(index: nil, delete: nil, create: nil, type: nil, suffix: nil, **options)
|
168
|
+
definition = {
|
169
|
+
index: index_name(suffix: suffix),
|
170
|
+
type: type,
|
171
|
+
}.merge(options)
|
172
|
+
cluster.may_update_type!(definition)
|
173
|
+
|
174
|
+
# @TODO Wrap the return in a some other Stats object with more information
|
175
|
+
Esse::Import::Bulk.new(
|
176
|
+
**definition.slice(:type),
|
177
|
+
index: index,
|
178
|
+
delete: delete,
|
179
|
+
create: create,
|
180
|
+
).each_request do |request_body|
|
181
|
+
cluster.api.bulk(**definition, body: request_body.body) do |event_payload|
|
182
|
+
event_payload[:body_stats] = request_body.stats
|
183
|
+
if bulk_wait_interval > 0
|
184
|
+
event_payload[:wait_interval] = bulk_wait_interval
|
185
|
+
sleep(bulk_wait_interval)
|
186
|
+
else
|
187
|
+
event_payload[:wait_interval] = 0.0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Resolve collection and index data
|
194
|
+
#
|
195
|
+
# @param repos [Array<String>] List of repo types. Defaults to all types.
|
196
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
197
|
+
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
198
|
+
# @option [Hash] :context The collection context. This value will be passed as argument to the collection
|
199
|
+
# May be SQL condition or any other filter you have defined on the collection.
|
200
|
+
# @return [Numeric] The number of documents imported
|
201
|
+
def import(*repo_types, context: {}, suffix: nil, **options)
|
202
|
+
repo_types = repo_hash.keys if repo_types.empty?
|
203
|
+
count = 0
|
204
|
+
repo_hash.slice(*repo_types).each do |repo_name, repo|
|
205
|
+
repo.each_serialized_batch(**(context || {})) do |batch|
|
206
|
+
# Elasticsearch 6.x and older have multiple types per index.
|
207
|
+
# This gem supports multiple types per index for backward compatibility, but we recommend to update
|
208
|
+
# your elasticsearch to a at least 7.x version and use a single type per index.
|
209
|
+
#
|
210
|
+
# Note that the repository name will be used as the document type.
|
211
|
+
# mapping_default_type
|
212
|
+
kwargs = { index: batch, suffix: suffix, type: repo_name, **options }
|
213
|
+
cluster.may_update_type!(kwargs)
|
214
|
+
bulk(**kwargs)
|
215
|
+
count += batch.size
|
216
|
+
end
|
217
|
+
end
|
218
|
+
count
|
219
|
+
end
|
220
|
+
|
221
|
+
protected
|
222
|
+
|
223
|
+
def document?(doc)
|
224
|
+
Esse.document?(doc)
|
225
|
+
end
|
226
|
+
|
227
|
+
def require_kwargs!(options, *keys)
|
228
|
+
keys.each do |key|
|
229
|
+
raise ArgumentError, "missing keyword: #{key}" unless options.key?(key)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
extend ClassMethods
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
class Index
|
5
|
+
module ClassMethods
|
6
|
+
CREATE_INDEX_RESERVED_KEYWORDS = {
|
7
|
+
alias: true,
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
# Creates index and applies mappings and settings.
|
11
|
+
#
|
12
|
+
# UsersIndex.create_index # creates index named `<cluster.index_prefix>users<index_suffix>`
|
13
|
+
#
|
14
|
+
# @param options [Hash] Options hash
|
15
|
+
# @option options [Boolean] :alias Update `index_name` alias along with the new index
|
16
|
+
# @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_suffix` or
|
17
|
+
# `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
|
18
|
+
# @option arguments [String] :wait_for_active_shards Set the number of active shards
|
19
|
+
# to wait for before the operation returns.
|
20
|
+
# @option arguments [Time] :timeout Explicit operation timeout
|
21
|
+
# @option arguments [Time] :master_timeout Specify timeout for connection to master
|
22
|
+
# @option arguments [Hash] :headers Custom HTTP headers
|
23
|
+
# @option arguments [Hash] :body The configuration for the index (`settings` and `mappings`)
|
24
|
+
# @raise [Esse::Transport::NotFoundError] when index already exists
|
25
|
+
# @return [Hash] the elasticsearch response
|
26
|
+
#
|
27
|
+
# @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
|
28
|
+
# @see Esse::Transport#create_index
|
29
|
+
def create_index(suffix: nil, **options)
|
30
|
+
options = CREATE_INDEX_RESERVED_KEYWORDS.merge(options)
|
31
|
+
name = build_real_index_name(suffix)
|
32
|
+
definition = [settings_hash, mappings_hash].reduce(&:merge)
|
33
|
+
|
34
|
+
if options.delete(:alias) && name != index_name
|
35
|
+
definition[:aliases] = { index_name => {} }
|
36
|
+
end
|
37
|
+
|
38
|
+
cluster.api.create_index(index: name, body: definition, **options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Deletes, creates and imports data to the index. Performs zero-downtime index resetting.
|
42
|
+
#
|
43
|
+
# @option options [String, nil] :suffix The index suffix. Defaults to the index_suffix.
|
44
|
+
# A uniq index name will be generated if one index already exist with the given alias.
|
45
|
+
# @option options [Time] :timeout Explicit operation timeout
|
46
|
+
# @raise [Esse::Transport::ServerError]
|
47
|
+
# in case of failure
|
48
|
+
# @return [Hash] the elasticsearch response
|
49
|
+
#
|
50
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
|
51
|
+
def reset_index(suffix: index_suffix, import: true, reindex: false, **options)
|
52
|
+
cluster.throw_error_when_readonly!
|
53
|
+
existing = []
|
54
|
+
suffix ||= Esse.timestamp
|
55
|
+
suffix = Esse.timestamp while index_exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
|
56
|
+
|
57
|
+
create_index(**options, suffix: suffix, alias: false)
|
58
|
+
if index_exist? && aliases.none?
|
59
|
+
cluster.api.delete_index(index: index_name)
|
60
|
+
end
|
61
|
+
if import
|
62
|
+
import(**options, suffix: suffix)
|
63
|
+
elsif reindex && (_from = indices_pointing_to_alias).any?
|
64
|
+
# @TODO: Reindex using the reindex API
|
65
|
+
end
|
66
|
+
update_aliases(suffix: suffix)
|
67
|
+
existing.each { |_s| delete_index!(**options, suffix: suffix) }
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Checks the index existance. Returns true or false
|
72
|
+
#
|
73
|
+
# UsersIndex.index_exist? #=> true
|
74
|
+
#
|
75
|
+
# @param options [Hash] Options hash
|
76
|
+
# @option options [String, nil] :suffix The index suffix
|
77
|
+
# @see Esse::Transport#index_exist?
|
78
|
+
def index_exist?(suffix: nil)
|
79
|
+
cluster.api.index_exist?(index: index_name(suffix: suffix))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Deletes an existing index.
|
83
|
+
#
|
84
|
+
# UsersIndex.delete_index # deletes `<cluster.index_prefix>users<index_suffix>` index
|
85
|
+
#
|
86
|
+
# @param suffix [String, nil] The index suffix Use nil if you want to delete the current index.
|
87
|
+
# @raise [Esse::Transport::NotFoundError] when index does not exists
|
88
|
+
# @return [Hash] elasticsearch response
|
89
|
+
def delete_index(suffix: nil, **options)
|
90
|
+
index = suffix ? index_name(suffix: suffix) : indices_pointing_to_alias.first
|
91
|
+
index ||= index_name
|
92
|
+
cluster.api.delete_index(**options, index: index)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Open a previously closed index
|
96
|
+
#
|
97
|
+
# @option options [String, nil] :suffix The index suffix
|
98
|
+
# @see Esse::Transport#open
|
99
|
+
def open(suffix: nil, **options)
|
100
|
+
cluster.api.open(index: index_name(suffix: suffix), **options)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Close an index (keep the data on disk, but deny operations with the index).
|
104
|
+
#
|
105
|
+
# @option options [String, nil] :suffix The index suffix
|
106
|
+
# @see Esse::Transport#close
|
107
|
+
def close(suffix: nil, **options)
|
108
|
+
cluster.api.close(index: index_name(suffix: suffix), **options)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Performs the refresh operation in one or more indices.
|
112
|
+
#
|
113
|
+
# @note The refresh operation can adversely affect indexing throughput when used too frequently.
|
114
|
+
# @param :suffix [String, nil] :suffix The index suffix
|
115
|
+
# @see Esse::Transport#refresh
|
116
|
+
def refresh(suffix: nil, **options)
|
117
|
+
cluster.api.refresh(index: index_name(suffix: suffix), **options)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Updates index mappings
|
121
|
+
#
|
122
|
+
# @param :suffix [String, nil] :suffix The index suffix
|
123
|
+
# @see Esse::Transport#update_mapping
|
124
|
+
def update_mapping(suffix: nil, **options)
|
125
|
+
body = mappings_hash.fetch(Esse::MAPPING_ROOT_KEY)
|
126
|
+
if (type = options[:type])
|
127
|
+
# Elasticsearch <= 5.x should submit request with type both in the path and in the body
|
128
|
+
# Elasticsearch 6.x should submit request with type in the path but not in the body
|
129
|
+
# Elasticsearch >= 7.x does not support type in the mapping
|
130
|
+
body = body[type.to_s] || body[type.to_sym] || body
|
131
|
+
end
|
132
|
+
cluster.api.update_mapping(index: index_name(suffix: suffix), body: body, **options)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Updates index settings
|
136
|
+
#
|
137
|
+
# @param :suffix [String, nil] :suffix The index suffix
|
138
|
+
# @see Esse::Transport#update_settings
|
139
|
+
def update_settings(suffix: nil, **options)
|
140
|
+
response = nil
|
141
|
+
|
142
|
+
settings = HashUtils.deep_transform_keys(settings_hash.fetch(Esse::SETTING_ROOT_KEY), &:to_s)
|
143
|
+
if options[:body]
|
144
|
+
settings = settings.merge(HashUtils.deep_transform_keys(options.delete(:body), &:to_s))
|
145
|
+
end
|
146
|
+
settings.delete('number_of_shards') # Can't change number of shards for an index
|
147
|
+
settings['index']&.delete('number_of_shards')
|
148
|
+
analysis = settings.delete('analysis')
|
149
|
+
|
150
|
+
if settings.any?
|
151
|
+
response = cluster.api.update_settings(index: index_name(suffix: suffix), body: settings, **options)
|
152
|
+
end
|
153
|
+
|
154
|
+
if analysis
|
155
|
+
# It is also possible to define new analyzers for the index. But it is required to close the
|
156
|
+
# index first and open it after the changes are made.
|
157
|
+
close(suffix: suffix)
|
158
|
+
begin
|
159
|
+
response = cluster.api.update_settings(index: index_name(suffix: suffix), body: { analysis: analysis }, **options)
|
160
|
+
ensure
|
161
|
+
self.open(suffix: suffix)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
response
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
extend ClassMethods
|
170
|
+
end
|
171
|
+
end
|
@@ -3,57 +3,6 @@
|
|
3
3
|
module Esse
|
4
4
|
class Index
|
5
5
|
module ObjectDocumentMapper
|
6
|
-
# Convert ruby object to json. Arguments will be same of passed through the
|
7
|
-
# collection. It's allowed a block or a class with the `to_h` instance method.
|
8
|
-
# Example with block
|
9
|
-
# serializer :user do |model, **context|
|
10
|
-
# {
|
11
|
-
# id: model.id,
|
12
|
-
# admin: context[:is_admin],
|
13
|
-
# }
|
14
|
-
# end
|
15
|
-
# Example with serializer class
|
16
|
-
# serializer UserSerializer
|
17
|
-
def serializer(*args, &block)
|
18
|
-
repo_name, klass = args
|
19
|
-
# >> Backward compatibility for the old collection syntax without explicit repo_name
|
20
|
-
if repo_name && klass.nil? && !repo_name.is_a?(String) && !repo_name.is_a?(Symbol)
|
21
|
-
klass = repo_name
|
22
|
-
repo_name = DEFAULT_REPO_NAME
|
23
|
-
end
|
24
|
-
repo_name = repo_name&.to_s || DEFAULT_REPO_NAME
|
25
|
-
# <<
|
26
|
-
find_or_define_repo(repo_name).serializer(klass, &block)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Used to define the source of data. A block is required. And its
|
30
|
-
# content should yield an array of each object that should be serialized.
|
31
|
-
# The list of arguments will be passed throught the serializer method.
|
32
|
-
#
|
33
|
-
# Example:
|
34
|
-
# collection :admin, AdminStore
|
35
|
-
# collection :user do |**conditions, &block|
|
36
|
-
# User.where(conditions).find_in_batches(batch_size: 5000) do |batch|
|
37
|
-
# block.call(batch, conditions)
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# @param [String] name The identification of the collection.
|
42
|
-
# @param [Class] klass The class of the collection. (Optional when block is passed)
|
43
|
-
# @param [Proc] block The block that will be used to iterate over the collection. (Optional when using a class)
|
44
|
-
# @return [void]
|
45
|
-
def collection(*args, **kwargs, &block)
|
46
|
-
repo_name, collection_klass = args
|
47
|
-
# >> Backward compatibility for the old collection syntax without explicit repo_name
|
48
|
-
if repo_name && !repo_name.is_a?(Symbol) && !repo_name.is_a?(String) && collection_klass.nil?
|
49
|
-
collection_klass = repo_name
|
50
|
-
repo_name = DEFAULT_REPO_NAME
|
51
|
-
end
|
52
|
-
repo_name = repo_name&.to_s || DEFAULT_REPO_NAME
|
53
|
-
# <<
|
54
|
-
find_or_define_repo(repo_name).collection(collection_klass, **kwargs, &block)
|
55
|
-
end
|
56
|
-
|
57
6
|
# Wrap collection data into serialized batches
|
58
7
|
#
|
59
8
|
# @param [String, NilClass] repo_name The repository identifier
|
@@ -80,14 +29,6 @@ module Esse
|
|
80
29
|
end
|
81
30
|
end
|
82
31
|
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def find_or_define_repo(repo_name)
|
87
|
-
return repo_hash[repo_name] if repo_hash.key?(repo_name)
|
88
|
-
|
89
|
-
repository(repo_name) {}
|
90
|
-
end
|
91
32
|
end
|
92
33
|
|
93
34
|
extend ObjectDocumentMapper
|
data/lib/esse/index/type.rb
CHANGED
@@ -24,7 +24,7 @@ module Esse
|
|
24
24
|
|
25
25
|
repository :#{name} do
|
26
26
|
# collection ...
|
27
|
-
#
|
27
|
+
# document ...
|
28
28
|
end
|
29
29
|
MSG
|
30
30
|
end
|
@@ -37,7 +37,7 @@ module Esse
|
|
37
37
|
|
38
38
|
def repository(repo_name, *_args, **kwargs, &block)
|
39
39
|
repo_class = Class.new(Esse::Repository)
|
40
|
-
kwargs[:const]
|
40
|
+
kwargs[:const] = true unless kwargs.key?(:const) # TODO Change this to false to avoid collisions with application classes
|
41
41
|
kwargs[:lazy_evaluate] ||= false
|
42
42
|
|
43
43
|
if kwargs[:const]
|
@@ -48,7 +48,6 @@ module Esse
|
|
48
48
|
|
49
49
|
repo_class.send(:define_singleton_method, :index) { index }
|
50
50
|
repo_class.send(:define_singleton_method, :repo_name) { repo_name.to_s }
|
51
|
-
repo_class.document_type = (kwargs[:document_type] || repo_name).to_s
|
52
51
|
|
53
52
|
plugins.each do |mod|
|
54
53
|
next unless mod.const_defined?(:RepositoryClassMethods, false)
|
data/lib/esse/index.rb
CHANGED
@@ -17,10 +17,11 @@ module Esse
|
|
17
17
|
require_relative 'index/settings'
|
18
18
|
require_relative 'index/mappings'
|
19
19
|
require_relative 'index/descendants'
|
20
|
-
require_relative 'index/backend'
|
21
20
|
require_relative 'index/object_document_mapper'
|
21
|
+
# Methods that use the cluster API
|
22
|
+
require_relative 'index/aliases'
|
23
|
+
require_relative 'index/indices'
|
22
24
|
require_relative 'index/search'
|
23
|
-
|
24
|
-
def_Index(::Esse)
|
25
|
+
require_relative 'index/documents'
|
25
26
|
end
|
26
27
|
end
|
data/lib/esse/null_document.rb
CHANGED
@@ -3,10 +3,9 @@
|
|
3
3
|
module Esse
|
4
4
|
class Repository
|
5
5
|
module ClassMethods
|
6
|
-
def
|
7
|
-
|
6
|
+
def import(**kwargs)
|
7
|
+
index.import(repo_name, **kwargs)
|
8
8
|
end
|
9
|
-
alias_method :backend, :elasticsearch
|
10
9
|
end
|
11
10
|
|
12
11
|
extend ClassMethods
|