esse 0.2.2 → 0.2.3
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/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
|